diff --git a/packages/neuron-ui/src/components/History/index.tsx b/packages/neuron-ui/src/components/History/index.tsx index 6ae473f369..378799d76a 100644 --- a/packages/neuron-ui/src/components/History/index.tsx +++ b/packages/neuron-ui/src/components/History/index.tsx @@ -17,9 +17,6 @@ import styles from './history.module.scss' const History = () => { const { - app: { - loadings: { transactionList: isLoading }, - }, wallet: { id, name: walletName }, chain: { networkID, @@ -111,7 +108,6 @@ const History = () => { keywords, onKeywordsChange, onSearch, - isLoading, id, walletName, items, diff --git a/packages/neuron-ui/src/components/MultisigAddress/hooks.ts b/packages/neuron-ui/src/components/MultisigAddress/hooks.ts index 46462b16e7..ca64a4709b 100644 --- a/packages/neuron-ui/src/components/MultisigAddress/hooks.ts +++ b/packages/neuron-ui/src/components/MultisigAddress/hooks.ts @@ -1,8 +1,9 @@ -import React, { useCallback, useState, useEffect } from 'react' -import { useDialogWrapper, isSuccessResponse } from 'utils' +import React, { useCallback, useState, useEffect, useMemo } from 'react' +import { useDialogWrapper, isSuccessResponse, getMultisigAddress, DefaultLockInfo } from 'utils' import { MultisigOutputUpdate } from 'services/subjects' import { MultisigConfig, + MultisigEntity, saveMultisigConfig, getMultisigConfig, importMultisigConfig, @@ -13,10 +14,10 @@ import { loadMultisigTxJson, OfflineSignJSON, } from 'services/remote' +import { addressToScript, scriptToAddress } from '@nervosnetwork/ckb-sdk-utils' -export const useSearch = (clearSelected: () => void) => { +export const useSearch = (clearSelected: () => void, onFilterConfig: (searchKey: string) => void) => { const [keywords, setKeywords] = useState('') - const [searchKeywords, setSearchKeywords] = useState('') const onKeywordsChange = (_e?: React.FormEvent, newValue?: string) => { if (undefined !== newValue) { @@ -26,90 +27,111 @@ export const useSearch = (clearSelected: () => void) => { const onSearch = useCallback( value => { - setSearchKeywords(value) + onFilterConfig(value) clearSelected() }, - [setSearchKeywords, clearSelected] + [onFilterConfig, clearSelected] ) const onClear = useCallback(() => { onSearch('') }, [onSearch]) - return { keywords, onKeywordsChange, setKeywords, onSearch, searchKeywords, onClear } + return { keywords, onKeywordsChange, setKeywords, onSearch, onClear } } export const useConfigManage = ({ walletId, isMainnet }: { walletId: string; isMainnet: boolean }) => { - const [configs, setConfigs] = useState([]) + const [entities, setEntities] = useState([]) const saveConfig = useCallback( - ({ m, n, r, addresses, fullPayload }) => { + ({ m, n, r, addresses }: { m: number; n: number; r: number; addresses: string[] }) => { return saveMultisigConfig({ m, n, r, - addresses, - fullPayload, + blake160s: addresses.map(v => addressToScript(v).args), walletId, }).then(res => { if (isSuccessResponse(res)) { - if (res.result) { - setConfigs(v => [res.result!, ...v]) - } + setEntities(v => (res.result ? [res.result, ...v] : v)) } else { throw new Error(typeof res.message === 'string' ? res.message : res.message.content) } }) }, - [walletId, setConfigs] + [walletId, setEntities] ) useEffect(() => { - getMultisigConfig({ - walletId, - }).then(res => { - if (isSuccessResponse(res)) { - setConfigs(res.result) + getMultisigConfig(walletId).then(res => { + if (isSuccessResponse(res) && res.result) { + setEntities(res.result) } }) - }, [setConfigs, walletId]) + }, [setEntities, walletId]) const updateConfig = useCallback( (id: number) => (alias: string | undefined) => { updateMultisigConfig({ id, alias: alias || '' }).then(res => { if (isSuccessResponse(res)) { - setConfigs(v => v.map(config => (config.id === res.result?.id ? res.result : config))) + setEntities(v => v.map(config => (res.result && config.id === res.result?.id ? res.result : config))) } }) }, - [setConfigs] + [setEntities] ) - const filterConfig = useCallback((key: string) => { - setConfigs(v => - v.filter(config => { - return config.alias?.includes(key) || config.fullPayload === key - }) - ) - }, []) const deleteConfigById = useCallback( (id: number) => { - setConfigs(v => v.filter(config => config.id !== id)) + setEntities(v => v.filter(config => config.id !== id)) }, - [setConfigs] + [setEntities] ) const onImportConfig = useCallback(() => { - importMultisigConfig({ isMainnet, walletId }).then(res => { + importMultisigConfig(walletId).then(res => { if (isSuccessResponse(res) && res.result) { const { result } = res if (result) { - setConfigs(v => [...result, ...v]) + setEntities(v => [...result, ...v]) } } }) - }, [walletId, isMainnet]) + }, [walletId]) + const [searchKeywords, setSearchKeywords] = useState('') + const onFilterConfig = useCallback( + (v: string) => { + setSearchKeywords(v) + }, + [setSearchKeywords] + ) + const allConfigs = useMemo( + () => + entities.map(entity => ({ + ...entity, + addresses: entity.blake160s.map(args => + scriptToAddress( + { + args, + codeHash: DefaultLockInfo.CodeHash, + hashType: DefaultLockInfo.HashType, + }, + isMainnet + ) + ), + fullPayload: getMultisigAddress(entity.blake160s, entity.r, entity.m, entity.n, isMainnet), + })), + [entities, isMainnet] + ) + const configs = useMemo( + () => + searchKeywords + ? allConfigs.filter(v => v.alias?.includes(searchKeywords) || v.fullPayload === searchKeywords) + : allConfigs, + [allConfigs, searchKeywords] + ) return { saveConfig, - allConfigs: configs, + allConfigs, updateConfig, deleteConfigById, - filterConfig, onImportConfig, + configs, + onFilterConfig, } } diff --git a/packages/neuron-ui/src/components/MultisigAddress/index.tsx b/packages/neuron-ui/src/components/MultisigAddress/index.tsx index c803c1bf5b..68e95209ea 100644 --- a/packages/neuron-ui/src/components/MultisigAddress/index.tsx +++ b/packages/neuron-ui/src/components/MultisigAddress/index.tsx @@ -53,7 +53,15 @@ const MultisigAddress = () => { }, [i18n.language]) const isMainnet = isMainnetUtil(networks, networkID) const { openDialog, closeDialog, dialogRef, isDialogOpen } = useDialogWrapper() - const { allConfigs, saveConfig, updateConfig, deleteConfigById, onImportConfig } = useConfigManage({ + const { + allConfigs, + saveConfig, + updateConfig, + deleteConfigById, + onImportConfig, + configs, + onFilterConfig, + } = useConfigManage({ walletId, isMainnet, }) @@ -96,17 +104,8 @@ const MultisigAddress = () => { onChangeCheckedAll, exportConfig, clearSelected, - } = useExportConfig(allConfigs) - const { keywords, onKeywordsChange, onSearch, searchKeywords, onClear } = useSearch(clearSelected) - const configs = useMemo( - () => - searchKeywords - ? allConfigs.filter(v => { - return v.alias?.includes(searchKeywords) || v.fullPayload === searchKeywords - }) - : allConfigs, - [allConfigs, searchKeywords] - ) + } = useExportConfig(configs) + const { keywords, onKeywordsChange, onSearch, onClear } = useSearch(clearSelected, onFilterConfig) const sendTotalBalance = useMemo(() => { if (sendAction.sendFromMultisig?.fullPayload) { return multisigBanlances[sendAction.sendFromMultisig.fullPayload] @@ -117,7 +116,6 @@ const MultisigAddress = () => {
{ }, [setN] ) - const isError = useMemo(() => { - return !m || !n || Number(m) > Number(n) + const errorI18nKey: string | undefined = useMemo(() => { + if (!m || !n) { + return 'm-n-required' + } + const numM = Number(m) + const numN = Number(n) + if (numM > numN) { + return 'm-less-equal-n' + } + if (numM < 1 || numM > 255 || numN < 1 || numN > 255) { + return 'm-n-between-0-255' + } + return undefined }, [m, n]) return { m, n, setMBySelect, setNBySelect, - isError, + errorI18nKey, } } @@ -117,17 +128,18 @@ export const useViewMultisigAddress = ({ const [multisigAddress, changeMultisigAddress] = useState('') useEffect(() => { if (step === Step.viewMultiAddress) { - createMultisigAddress({ - r, - m, - n, - addresses, - isMainnet, - }).then(res => { - if (isSuccessResponse(res) && res.result) { - changeMultisigAddress(res.result) - } - }) + try { + const address = getMultisigAddress( + addresses.map(v => addressToScript(v).args), + r, + m, + n, + isMainnet + ) + changeMultisigAddress(address) + } catch (error) { + // ignore error. The ui ensures the correctness of the parameters + } } }, [step, changeMultisigAddress, m, n, r, addresses, isMainnet]) return multisigAddress diff --git a/packages/neuron-ui/src/components/MultisigAddressCreateDialog/index.tsx b/packages/neuron-ui/src/components/MultisigAddressCreateDialog/index.tsx index 09e3201315..53f9f5a302 100644 --- a/packages/neuron-ui/src/components/MultisigAddressCreateDialog/index.tsx +++ b/packages/neuron-ui/src/components/MultisigAddressCreateDialog/index.tsx @@ -18,11 +18,13 @@ const SetMN = ({ n, changeM, changeN, + errorI18nKey, }: { m: string n: string changeM: (v: string) => void changeN: (v: string) => void + errorI18nKey?: string }) => { const [t] = useTranslation() return ( @@ -34,9 +36,7 @@ const SetMN = ({     of    
- {m && n && Number(m) > Number(n) && ( - {t('multisig-address.create-dialog.m-n.error')} - )} + {errorI18nKey && {t(`multisig-address.create-dialog.m-n.${errorI18nKey}`)}}
) } @@ -46,11 +46,11 @@ const MultisigAddressCreateDialog = ({ confirm: saveConfig, }: { closeDialog: () => void - confirm: (v: Omit) => Promise + confirm: (v: Omit) => Promise }) => { const [step, changeStep] = useState(Step.setMN) const [t] = useTranslation() - const { m, n, setMBySelect, setNBySelect, isError: mnErr } = useMAndN() + const { m, n, setMBySelect, setNBySelect, errorI18nKey: mnErr } = useMAndN() const next = useCallback(() => { changeStep(step + 1) }, [changeStep, step]) @@ -87,18 +87,17 @@ const MultisigAddressCreateDialog = ({ saveConfig({ m: Number(m), n: Number(n), - r, + r: Number(r), addresses, - fullPayload: multisigAddress, }).then(() => { closeDialog() }) - }, [m, n, r, addresses, multisigAddress, saveConfig, closeDialog]) + }, [m, n, r, addresses, saveConfig, closeDialog]) return ( <>

{t('multisig-address.create-dialog.title')}

- {step === Step.setMN && } + {step === Step.setMN && } {step === Step.setMultiAddress && ( <>

{t('multisig-address.create-dialog.multi-address-info.title', { m, n })}

@@ -126,7 +125,7 @@ const MultisigAddressCreateDialog = ({