From 20269219177ce7b7a77ea976fcecfc80ad26a3c4 Mon Sep 17 00:00:00 2001 From: Keith Date: Mon, 11 Nov 2019 10:26:01 +0800 Subject: [PATCH] feat: verify address according to chain type --- packages/neuron-ui/src/components/Send/hooks.ts | 10 ++++++++-- packages/neuron-ui/src/components/Send/index.tsx | 7 +++++-- packages/neuron-ui/src/locales/en.json | 2 ++ packages/neuron-ui/src/locales/zh.json | 2 ++ packages/neuron-ui/src/utils/validators.ts | 8 +++++++- packages/neuron-wallet/src/controllers/wallets.ts | 11 +++++++++++ packages/neuron-wallet/src/exceptions/address.ts | 15 ++++++++++++++- packages/neuron-wallet/src/locales/en.ts | 4 +++- packages/neuron-wallet/src/locales/zh.ts | 4 +++- 9 files changed, 55 insertions(+), 8 deletions(-) diff --git a/packages/neuron-ui/src/components/Send/hooks.ts b/packages/neuron-ui/src/components/Send/hooks.ts index 03f99089ee..e43629b886 100644 --- a/packages/neuron-ui/src/components/Send/hooks.ts +++ b/packages/neuron-ui/src/components/Send/hooks.ts @@ -201,11 +201,17 @@ export const useInitialize = ( clear(dispatch) }, [walletID, dispatch]) - const onGetAddressErrorMessage = useCallback( - (addr: string) => { + const onGetAddressErrorMessage: (isMainnet: boolean) => (addr: string) => string = useCallback( + (isMainnet: boolean) => (addr: string) => { if (addr === '') { return t(`messages.codes.${ErrorCode.AddressIsEmpty}`) } + if (isMainnet && !addr.startsWith('ckb')) { + return t(`messages.mainnet-address-required`) + } + if (!isMainnet && !addr.startsWith('ckt')) { + return t(`messages.testnet-address-required`) + } if (!verifyAddress(addr)) { return t(`messages.codes.${ErrorCode.FieldInvalid}`, { fieldName: 'address', diff --git a/packages/neuron-ui/src/components/Send/index.tsx b/packages/neuron-ui/src/components/Send/index.tsx index d6361f09c0..97630eb40b 100644 --- a/packages/neuron-ui/src/components/Send/index.tsx +++ b/packages/neuron-ui/src/components/Send/index.tsx @@ -38,7 +38,8 @@ const Send = ({ loadings: { sending = false }, }, wallet: { id: walletID = '', balance = '' }, - chain: { connectionStatus }, + chain: { networkID, connectionStatus }, + settings: { networks = [] }, dispatch, }: React.PropsWithoutRef>) => { const { t } = useTranslation() @@ -66,6 +67,8 @@ const Send = ({ const errorMessageUnderTotal = verifyTotalAmount(totalAmount, fee, balance) ? errorMessage : t(`messages.codes.${ErrorCode.AmountNotEnough}`) + const network = networks.find(n => n.id === networkID) + const isMainnet = (network && network.chain === 'ckb') || false // TODO: shoudl be replaced after the mainnet tag is introduced return ( @@ -97,7 +100,7 @@ const Send = ({ onChange={onItemChange} required validateOnLoad={false} - onGetErrorMessage={onGetAddressErrorMessage} + onGetErrorMessage={onGetAddressErrorMessage(isMainnet)} /> diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index eb07aa5946..8d246a39f4 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -273,6 +273,8 @@ "keystore-password": "Password", "deposit": "Deposit" }, + "mainnet-address-required": "Please enter a mainnet address", + "testnet-address-required": "Please enter a testnet address", "codes": { "-3": "", "100": "Amount is not enough", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index d79846dac7..6f0facc722 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -273,6 +273,8 @@ "keystore-password": "密码", "deposit": "存入金额" }, + "mainnet-address-required": "请输入主网地址", + "testnet-address-required": "请输出测试网地址", "codes": { "-3": "", "100": "余额不足", diff --git a/packages/neuron-ui/src/utils/validators.ts b/packages/neuron-ui/src/utils/validators.ts index 23727dfd2c..868dcd50ee 100644 --- a/packages/neuron-ui/src/utils/validators.ts +++ b/packages/neuron-ui/src/utils/validators.ts @@ -10,10 +10,16 @@ import { import { CKBToShannonFormatter } from 'utils/formatters' import { ckbCore } from 'services/chain' -export const verifyAddress = (address: string): boolean => { +export const verifyAddress = (address: string, isMainnet?: boolean): boolean => { if (typeof address !== 'string' || address.length !== 46) { return false } + if (isMainnet === true && !address.startsWith('ckb')) { + return false + } + if (isMainnet === false && !address.startsWith('ckt')) { + return false + } try { return ckbCore.utils.parseAddress(address, 'hex').startsWith('0x0100') } catch (err) { diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts index 0491f7952d..66f9ec8fe3 100644 --- a/packages/neuron-wallet/src/controllers/wallets.ts +++ b/packages/neuron-wallet/src/controllers/wallets.ts @@ -4,6 +4,7 @@ import { dialog, SaveDialogReturnValue, BrowserWindow } from 'electron' import WalletsService, { Wallet, WalletProperties, FileKeystoreWallet } from 'services/wallets' import Keystore from 'models/keys/keystore' import Keychain from 'models/keys/keychain' +import ChainInfo from 'models/chain-info' import { validateMnemonic, mnemonicToSeedSync } from 'models/keys/mnemonic' import { AccountExtendedPublicKey, ExtendedPrivateKey } from 'models/keys/key' import { ResponseCode } from 'utils/const' @@ -22,6 +23,7 @@ import i18n from 'utils/i18n' import AddressService from 'services/addresses' import WalletCreatedSubject from 'models/subjects/wallet-created-subject' import { TransactionWithoutHash, OutPoint } from 'types/cell-types' +import { MainnetAddressRequired, TestnetAddressRequired } from 'exceptions/address' export default class WalletsController { public static async getAll(): Promise[]>> { @@ -339,7 +341,16 @@ export default class WalletsController { feeRate = '1000' } + const isMainnet = ChainInfo.getInstance().isMainnet() params.items.forEach(item => { + if (isMainnet && !item.address.startsWith('ckb')) { + throw new MainnetAddressRequired(item.address) + } + + if (!isMainnet && !item.address.startsWith('ckt')) { + throw new TestnetAddressRequired(item.address) + } + if (!this.verifyAddress(item.address)) { throw new InvalidAddress(item.address) } diff --git a/packages/neuron-wallet/src/exceptions/address.ts b/packages/neuron-wallet/src/exceptions/address.ts index 2daac7dd8a..2a2fcd55d3 100644 --- a/packages/neuron-wallet/src/exceptions/address.ts +++ b/packages/neuron-wallet/src/exceptions/address.ts @@ -5,4 +5,17 @@ export class InvalidAddress extends Error { super(i18n.t('invalid-address', { address })) } } -export default { InvalidAddress } + +export class MainnetAddressRequired extends Error { + constructor(address: string) { + super(i18n.t('mainnet-address-required', { address })) + } +} + +export class TestnetAddressRequired extends Error { + constructor(address: string) { + super(i18n.t('testnet-address-required', { address })) + } +} + +export default { InvalidAddress, MainnetAddressRequired, TestnetAddressRequired } diff --git a/packages/neuron-wallet/src/locales/en.ts b/packages/neuron-wallet/src/locales/en.ts index 5bff63e416..a437ec3d14 100644 --- a/packages/neuron-wallet/src/locales/en.ts +++ b/packages/neuron-wallet/src/locales/en.ts @@ -93,7 +93,9 @@ export default { 'invalid-keystore': 'Keystore is invalid', 'invalid-json': 'Invalid JSON file', 'cell-is-not-yet-live': 'Cell is not yet live!', - 'transaction-is-not-committed-yet': 'Transaction is not committed yet!' + 'transaction-is-not-committed-yet': 'Transaction is not committed yet!', + 'mainnet-address-required': '{{address}} is not a mainnet address', + 'testnet-address-required': '{{address}} is not a testnet address' }, contextMenu: { select: 'Select', diff --git a/packages/neuron-wallet/src/locales/zh.ts b/packages/neuron-wallet/src/locales/zh.ts index fa8d3b2908..c77849b7c2 100644 --- a/packages/neuron-wallet/src/locales/zh.ts +++ b/packages/neuron-wallet/src/locales/zh.ts @@ -92,7 +92,9 @@ export default { 'invalid-keystore': 'Keystore 格式不正确', 'invalid-json': 'JSON 文件格式不正确', 'cell-is-not-yet-live': 'Cell 尚未激活', - 'transaction-is-not-committed-yet': '交易未提交' + 'transaction-is-not-committed-yet': '交易未提交', + 'mainnet-address-required': '{{address}} 不是主网地址', + 'testnet-address-required': '{{address}} 不是测试网地址' }, contextMenu: { select: '选择',