From 7d1faabb3d8f0e63419e570cbe5d3c4cec460f43 Mon Sep 17 00:00:00 2001 From: yanguoyu <841185308@qq.com> Date: Wed, 13 Mar 2024 09:18:05 +0800 Subject: [PATCH 1/2] fix: Adapt hard wallet for lock and unlock live cell. --- .../CellManagement/cellManagement.module.scss | 22 ++- .../src/components/CellManagement/hooks.ts | 135 +++++++++++++++++- .../src/components/CellManagement/index.tsx | 129 ++++++++++++----- packages/neuron-ui/src/locales/en.json | 3 +- packages/neuron-ui/src/locales/es.json | 3 +- packages/neuron-ui/src/locales/fr.json | 3 +- packages/neuron-ui/src/locales/zh-tw.json | 3 +- packages/neuron-ui/src/locales/zh.json | 3 +- .../neuron-ui/src/widgets/Icons/Hardware.png | Bin 0 -> 14718 bytes packages/neuron-wallet/src/controllers/api.ts | 2 +- .../src/controllers/cell-management.ts | 4 +- 11 files changed, 257 insertions(+), 50 deletions(-) create mode 100755 packages/neuron-ui/src/widgets/Icons/Hardware.png diff --git a/packages/neuron-ui/src/components/CellManagement/cellManagement.module.scss b/packages/neuron-ui/src/components/CellManagement/cellManagement.module.scss index 14ed375b5a..c286a5007a 100644 --- a/packages/neuron-ui/src/components/CellManagement/cellManagement.module.scss +++ b/packages/neuron-ui/src/components/CellManagement/cellManagement.module.scss @@ -163,9 +163,9 @@ @include checkbox; .multiActions { - position: absolute; + position: fixed; bottom: 24px; - left: 50%; + left: calc(50% + 80px); transform: translateX(-50%); padding: 12px 40px 12px 40px; border-radius: 40px; @@ -235,4 +235,22 @@ margin-right: 4px; } } + + .hardWalletImg { + width: 88px; + height: 88px; + margin: 16px 0 24px 0; + } + + .lockActions { + margin-top: 24px; + display: flex; + justify-content: center; + gap: 16px; + } + + .hardwalletErr { + justify-content: center; + margin-top: 12px; + } } diff --git a/packages/neuron-ui/src/components/CellManagement/hooks.ts b/packages/neuron-ui/src/components/CellManagement/hooks.ts index 9076750ece..32ec3904a2 100644 --- a/packages/neuron-ui/src/components/CellManagement/hooks.ts +++ b/packages/neuron-ui/src/components/CellManagement/hooks.ts @@ -1,12 +1,20 @@ +import { CkbAppNotFoundException, DeviceNotFoundException } from 'exceptions' +import { TFunction } from 'i18next' import { useCallback, useEffect, useMemo, useState } from 'react' import { useNavigate } from 'react-router-dom' import { + connectDevice, + getDeviceCkbAppVersion, + getDevices, getLiveCells, + getPlatform, updateLiveCellsLocalInfo, updateLiveCellsLockStatus as updateLiveCellsLockStatusAPI, + updateWallet, } from 'services/remote' +import { ControllerResponse } from 'services/remote/remoteApiWrapper' import { AppActions, useDispatch } from 'states' -import { LockScriptCategory, RoutePath, TypeScriptCategory, isSuccessResponse, outPointToStr } from 'utils' +import { ErrorCode, LockScriptCategory, RoutePath, TypeScriptCategory, isSuccessResponse, outPointToStr } from 'utils' import { SortType } from 'widgets/Table' const cellTypeOrder: Record = { @@ -204,6 +212,7 @@ export const useAction = ({ resetPassword, setError, password, + verifyDeviceStatus, }: { liveCells: State.LiveCellWithLocalInfo[] currentPageLiveCells: State.LiveCellWithLocalInfo[] @@ -212,6 +221,7 @@ export const useAction = ({ resetPassword: () => void setError: (error: string) => void password: string + verifyDeviceStatus: () => Promise }) => { const dispatch = useDispatch() const navigate = useNavigate() @@ -219,7 +229,7 @@ export const useAction = ({ const [operateCells, setOperateCells] = useState([]) const [loading, setLoading] = useState(false) const onOpenActionDialog = useCallback( - (e: React.SyntheticEvent) => { + async (e: React.SyntheticEvent) => { e.stopPropagation() const { action: curAction, index } = e.currentTarget.dataset as { action: Actions; index: string } if (!curAction || index === undefined || !currentPageLiveCells[+index]) return @@ -227,24 +237,27 @@ export const useAction = ({ setOperateCells([operateCell]) setAction(curAction) resetPassword() + await verifyDeviceStatus() }, [currentPageLiveCells, setOperateCells, dispatch, navigate] ) const onMultiAction = useCallback( - (e: React.SyntheticEvent) => { + async (e: React.SyntheticEvent) => { e.stopPropagation() const { action: curAction } = e.currentTarget.dataset as { action: Actions } if (!curAction || !selectedOutPoints.size) return setOperateCells(liveCells.filter(v => selectedOutPoints.has(outPointToStr(v.outPoint)))) setAction(curAction) resetPassword() + await verifyDeviceStatus() }, [liveCells, selectedOutPoints, setOperateCells, dispatch, navigate] ) - const onActionConfirm = useCallback(() => { + const onActionConfirm = useCallback(async () => { switch (action) { case 'lock': case 'unlock': + if (!(await verifyDeviceStatus())) return setLoading(true) updateLiveCellsLockStatus({ outPoints: operateCells.map(v => v.outPoint), @@ -362,3 +375,117 @@ export const usePassword = () => { resetPassword, } } + +export const useHardWallet = ({ wallet, t }: { wallet: State.WalletIdentity; t: TFunction }) => { + const isWin32 = useMemo(() => { + return getPlatform() === 'win32' + }, []) + const [error, setError] = useState() + const disconnectStatus = t('hardware-verify-address.status.disconnect') + const ckbAppNotFoundStatus = t(CkbAppNotFoundException.message) + const isNotAvailable = useMemo(() => { + return error === disconnectStatus || error === ckbAppNotFoundStatus + }, [error, disconnectStatus, ckbAppNotFoundStatus]) + + const [deviceInfo, setDeviceInfo] = useState(wallet.device) + const [isReconnecting, setIsReconnecting] = useState(false) + + const ensureDeviceAvailable = useCallback( + async (device: State.DeviceInfo) => { + try { + const connectionRes = await connectDevice(device) + let { descriptor } = device + if (!isSuccessResponse(connectionRes)) { + // for win32, opening or closing the ckb app changes the HID descriptor(deviceInfo), + // so if we can't connect to the device, we need to re-search device automatically. + // for unix, the descriptor never changes unless user plugs the device into another USB port, + // in that case, mannauly re-search device one time will do. + if (isWin32) { + setIsReconnecting(true) + const devicesRes = await getDevices(device) + setIsReconnecting(false) + if (isSuccessResponse(devicesRes) && Array.isArray(devicesRes.result) && devicesRes.result.length > 0) { + const [updatedDeviceInfo] = devicesRes.result + descriptor = updatedDeviceInfo.descriptor + setDeviceInfo(updatedDeviceInfo) + } else { + throw new DeviceNotFoundException() + } + } else { + throw new DeviceNotFoundException() + } + } + + // getDeviceCkbAppVersion will halt forever while in win32 sleep mode. + const ckbVersionRes = await Promise.race([ + getDeviceCkbAppVersion(descriptor), + new Promise((_, reject) => { + setTimeout(() => reject(), 1000) + }), + ]).catch(() => { + return { status: ErrorCode.DeviceInSleep } + }) + + if (!isSuccessResponse(ckbVersionRes)) { + if (ckbVersionRes.status !== ErrorCode.DeviceInSleep) { + throw new CkbAppNotFoundException() + } else { + throw new DeviceNotFoundException() + } + } + setError(undefined) + return true + } catch (err) { + if (err instanceof CkbAppNotFoundException) { + setError(ckbAppNotFoundStatus) + } else { + setError(disconnectStatus) + } + return false + } + }, + [disconnectStatus, ckbAppNotFoundStatus, isWin32] + ) + + const reconnect = useCallback(async () => { + if (!deviceInfo) return + setError(undefined) + setIsReconnecting(true) + try { + const res = await getDevices(deviceInfo) + if (isSuccessResponse(res) && Array.isArray(res.result) && res.result.length > 0) { + const [device] = res.result + setDeviceInfo(device) + if (device.descriptor !== deviceInfo.descriptor) { + await updateWallet({ + id: wallet.id, + device, + }) + } + await ensureDeviceAvailable(device) + } else { + setError(disconnectStatus) + } + } catch (err) { + setError(disconnectStatus) + } finally { + setIsReconnecting(false) + } + }, [deviceInfo, disconnectStatus, ensureDeviceAvailable, wallet.id]) + + const verifyDeviceStatus = useCallback(async () => { + if (deviceInfo) { + return ensureDeviceAvailable(deviceInfo) + } + return true + }, [ensureDeviceAvailable, deviceInfo]) + return { + deviceInfo, + isReconnecting, + isNotAvailable, + reconnect, + verifyDeviceStatus, + error, + setError, + } +} diff --git a/packages/neuron-ui/src/components/CellManagement/index.tsx b/packages/neuron-ui/src/components/CellManagement/index.tsx index e8752c869c..864edd3f62 100644 --- a/packages/neuron-ui/src/components/CellManagement/index.tsx +++ b/packages/neuron-ui/src/components/CellManagement/index.tsx @@ -23,7 +23,10 @@ import TextField from 'widgets/TextField' import { useSearchParams } from 'react-router-dom' import CellInfoDialog from 'components/CellInfoDialog' import { computeScriptHash } from '@ckb-lumos/base/lib/utils' -import { Actions, useAction, useLiveCells, usePassword, useSelect } from './hooks' +import Hardware from 'widgets/Icons/Hardware.png' +import Button from 'widgets/Button' +import Alert from 'widgets/Alert' +import { Actions, useAction, useHardWallet, useLiveCells, usePassword, useSelect } from './hooks' import styles from './cellManagement.module.scss' const getColumns = ({ @@ -214,7 +217,7 @@ const getColumns = ({ const CellManagement = () => { const { app: { epoch }, - wallet: { balance = '' }, + wallet, chain: { syncState: { bestKnownBlockTimestamp }, }, @@ -236,6 +239,17 @@ const CellManagement = () => { return liveCells.slice(pageSize * (pageNo - 1), pageSize * pageNo) }, [pageNo, pageSize, liveCells]) const { onSelect, onSelectAll, isAllSelected, selectedOutPoints, hasSelectLocked, isAllLocked } = useSelect(liveCells) + const { + isReconnecting, + isNotAvailable, + reconnect, + verifyDeviceStatus, + error: hardwalletError, + setError: setHardwalletError, + } = useHardWallet({ + wallet, + t, + }) const { password, error, onPasswordChange, setError, resetPassword } = usePassword() const { action, operateCells, onActionCancel, onActionConfirm, onOpenActionDialog, onMultiAction, loading } = useAction({ @@ -243,9 +257,10 @@ const CellManagement = () => { currentPageLiveCells, updateLiveCellsLockStatus, selectedOutPoints, - setError, + setError: wallet.device ? setHardwalletError : setError, resetPassword, password, + verifyDeviceStatus, }) const columns = useMemo( () => @@ -285,7 +300,7 @@ const CellManagement = () => { {showBalance ? : } {t('cell-manage.wallet-balance')}    - {`${showBalance ? shannonToCKBFormatter(balance) : HIDE_BALANCE} CKB`} + {`${showBalance ? shannonToCKBFormatter(wallet.balance) : HIDE_BALANCE} CKB`} } @@ -330,38 +345,80 @@ const CellManagement = () => { } onCancel={onActionCancel} /> - -

- {t(`cell-manage.cell-${action}-dialog.capacity`, { capacity: totalCapacity })} -

- - {action === Actions.Lock ? ( - - - {t('cell-manage.cell-lock-dialog.locked-cell-can-not-use')} - - ) : null} -
+ {wallet.device ? ( + +

+ {t(`cell-manage.cell-${action}-dialog.capacity`, { capacity: totalCapacity })} +

+
+ hard-wallet +
+ {action === Actions.Lock ? ( + + + {t('cell-manage.cell-lock-dialog.locked-cell-can-not-use')} + + ) : null} +
+ + +
+ {hardwalletError ? ( + + {hardwalletError} + + ) : null} +
+ ) : ( + +

+ {t(`cell-manage.cell-${action}-dialog.capacity`, { capacity: totalCapacity })} +

+ + {action === Actions.Lock ? ( + + + {t('cell-manage.cell-lock-dialog.locked-cell-can-not-use')} + + ) : null} +
+ )} EWB?f>@5FLMhKwF6Z5Cs5g;t^ksU;qGKOquVZs-D1eKg4QAEv=1@2mc(u z4UdaUSj!!2AHI*uAHb#{Ofioc9SzuC^MUy$~s58QtJ zUGb1K{g}JcBlU4T$lP|g6Hg*)^KC$#psVV={Nw3An-1@nIN<%HYt89H^7F0EA13rW zZs6B4<`E;5g0J~b#jCs{xKF=Y9OwG?Xnyad-N58r>L(Kcuy<{P3f@`p#|Jp*qI_Fs zPl-wV7@8mRNxipTF9mP>FfGsN?dcJ>G=v{tJ{(V5#`zbGSkA<7`O?ANj3;tzgeQvP z_?-Uq8nT?7B}q{<2;?PkP2gWR9Qi0Q74Sge}5yp0*?d|bCnb9f{AJ$%@`xL(;tJaPc3xtj%v6eDbQCoDE=RI zguQoZ5B0VsGe!G)c1I6aa&CjtKkHyU@8I#MrE0GlN)*n1f_&QJcY3yZ!cEc5M1wL{ z0N!y&hXeXfpC*khsWwW+)l)77+ ztn~s_84B4OD+iDTd(iMs$MDfVzBrQSxryzn*SEtMBN*F#!0QNV=ZlR(z}xfS0)H-MC`_p=sg@dT!3c|6x`6IQMnj{{`_hhx-H8R}KNWAq8|*PU1JIXq&y_ zJIjXxwh$)%v3(CRgWztA>-k=Bd>o*5eu>k+8C zj_HwnkG}-#)Zz?P5S7Xa0=C3=cKwuOrM6rk$66~ zg|2%3Tm1XM-!iX~2>h{pq!-}Y;&F0$UvpU4v$q5Ey}`Wz_Xoe^UdON+;($W*JK^;1 z^2de#VW(rlm=jR%H$n-bU=P88q&AZ2ha9U9%4q#|~hkn0>ApAxEU zmT4(qC}?OHIC#EibbuIKN^A?i^YY|1D9oZitNDfzNMIXi$O#JR*?L#K4*&k;hPRMK zg()laxd`fgmbp^!gL8`IvxfNg>RHdJ6tEb=<$cQwG13aExA zCLr(CQ>6-XbW%t#DZ>e@42Zc1-s0u9B#yOYL`_5p`^18 z zU=u8-jHsz^JQV)@0+|#Qw=Kl;bTW6$@wOFQ z6q(`j-eRRO$2Sa$aXR~gMWpk}8oX(dLW(#@yDV%Pwfbf_We8R-2=wcPACmiWn-$bs zSwI)$%N5ppOY!qAJg9g7%cNq$MsN>N3>I1^&GUhRi6{it;AExEiKy=8C8s zxgI8#bte@+7|=~(9kqMN0Q4fizL&bK`BMrDBdgQFBT3y;o0 z*>!5(KNuHDtPQvwfW&0(S{B)kkq(M{oA@rz)E6`mJ(Dy8a#{`_stk{C2T9uGM4~f3 z5pmB>A}Fme0X6lTh&pCIgJX+bUU$WvaJF(x6+-XIY*lD++rOuTtRkX}cqZRx+=F3y zeRxvO@%5_*HcN0N7C5=rl%F>z!Y?|SB2VNOphf@y2Zcz1$b=G;gl#hsC~^Rq>YE9U zfF|Sd)YCLBeU#Q(VVJ(5PoioAYr%8@;zgO6+ug4k!V-rW^s>J)6qRY{rUgo&swSTc zY#I3C;25+aakt;YAz40=x?A1y8e|9Dt}BM2ih>vdv1?7i#r#XaVzGuFOlMxa-Fk8p z3CEFmzS~4Kx>C7BwZG7t}l$~CRq$->0JPx8=e#{}1ygc}mJ2J!IT(}w{5*X9NZ1odCe#obu7bt^Aib?_B^@5{>n{J-i z{Dug%gosSOLo{e-5@^(l>G2?v4>8d*mxL1uYVB~zB|r1Rj!!utG0YwQsq<9i(g#vD z`fd&&Djva#casIY<7Q>RMb$RDU&G<6PI9Q>f9WapUzDT_;SCuc{(DSbJLba`(7}vG zYf_LPxA`ta^M{0#8(E;_TiJz-+i0 zpk^8~z|PZU)?rvQF41XYFrr1&6{DW@jx-g#{nWgG+Iw=G>Gepz`WlFFbD?7GS_W=I zSVLP_#Ok}HM~wPX&f#!4$2T;}w5#`ed3HO6rb7#$55IIX!*%egvp{HD_C(2sGr@sP zh|Q{wKb=NnDvQ@TN=Ii@A)kNr7su91`O0>aF1k)Wz4ad%GhMcfQ*h!a$S?+V`c5N5 zP{?C<#m4q9n&G0@K4{=yUnLUQ;IV$OvQ&K)0*Y#Za0N@+4NCvh122SKNyjK2Cd2vgY6zO}0?=pK18 zjo8l`(tNqfMDj^UGr+6cgTM%61q)Dh@{Mx2#Rs%k6Koc5(UeY z*H>FUHze)ZbcC(s8PNrdI}&I^n6U3aSB<^^ILW)IV!nekf~--j+^UQFOy;aU=2*jf zpZHhL)d-*exH3!?*_b#M#xoTT!3iva#of~X1@4q-z8^A}mrqq7kP8qxqb;z|tui+9 zM$4&Fp}ygn8nGx?#>nUqvh!GI=rsKd+kM(wBkYR%&k?mTyx{@K!WEsslpeHo;qFXV z!@epjF3n5|69hBJAbKk6m~XhBE()5;pCLo6NsKpOvvkv>21AF$gldwP$l_ioU>-i& zn5hZV%Wval2I)3S1_-rkkRdjuDMtmG92@p9RkJ>8td0P9R*Tt*rF&vEP`zB=*|IKF z=1X*$eFPEq+7aR$eu|(J29cqxchxJ00pyZ_P^I_Ux&(2|@1A^2!dtg=0j)gc z)yXiNScV8zK@6U~DywA6tNN?j*It$hpJ&U@@5omJTGrd8^w~?OVf;>*Z$tqO%kCU0 zmVw$(o8n!<;2)&IuD60e4^(jK{qntpr;UMMt#nr`xfSkAcd!fIt&AIhLq3F&WG2RP zebqwjBuwMWBpUpArZLGI$*~&^d2`&tzklW6U4ssA))e=Sro%&qY`~)`aQ}+0>~%?? zeDzKJ^Pt!gNlD9is$>Y>u5RM`{+o7sCJ}qCg zk*$|D`G;p_DjG@%Y+v0kwYrr*2d+qGu~sGzfOD&@Bm8CYT|>9S=tr$ZXQf{l9NPgU zH~r|We!2g>Iu;-lXryOoW?%3mYPLOk6FfF zid+P+6IK?_ojEdj+bc-?)vk4ZQ?q=7-)-UBef&{$rR<-lR&Ld zsD24k6V^tPmZJ>-_4EWwCc_mch;ZMmj-Py9j)Rfl1Qx(y@03rY^9oIG<_s&P<9vOB zuP~vs^dj*&{6`J$dq@mNc;D+PKx4tS`647w;mVj7exb&VQdrv(I zY8O78FMxOy91FU-MBHdg!TK4RAoAK~4rMv@^0&N5DkL7oTQM>MB_t6c;v{7D+kUVD z5;bJHp9&Z$CW-DC*bh{j6lW0q4}~O=wz0DJxL3XqV`roElJ}t&YY*RnggAhx_pFizFl^n?2>T^F`1>L7m z)5~j6!QKA@H;A`M9}QZYL}Lo3K@lbF8@;T?(cd$~IseNThE?aq1JY6K>9$=EF1K&- z33i~`|JHwxTFa>x^dDe%Dw?H14QWgPII>AYj+fMov(4g%8bd6ILq?DgCI+xbVm-k` znn2xd0iM@mB2DrbW-=^<_+OmRnuA?2ZsQ%6V1doN68NS}z|Je%9Y#yMcz*O{EPqui zKaxjK&)dlTt)!c=<>xLuqW8*mP5P&QaOuIPZfn=lVbZ0zQbAkrb;8-acA)J67MIt8 zyHxIG^4HKkH)s)rQMf0p)KdFiczqW4F~8!YqdLahKvgSSoVLv7vzSP?)w z-0Y@`7X4r=STPH+_JP=P+rN|FVQT(tfyIS|kwv|Ee8s;|Ms&%=N-HD?NM$Q#BjW35 zsKwFukXQ;0$}@u&SMd6w(A)s_vy*^l;Fy2 zF(tjRs=2buWuJn7t;%yR6v~j5ooSjN2(&oT6vn3e{S;;SGVtyG8$=vZXI7=ri1|k; z$!mU7Zyy9%Fg{uOIb9Mcu%ZstmA<3JjqyW=FIU{jbkj<#R(5|?ACCP8kz6RiGG+;n zuG20^)FdsC$Ov(2ND`|StkepQj9nSjYA>StMTAX#qX9beURGoI0@P%*^oAjsLVT+U zI_RcNoibPLeL>x2nqy zl$zPy*!2Es=(R0(lQBeq0wok_lepSco@vL(O(|NL0WLKq)i?2h+P=fk56KAXc=hst z>Aa{PSZJhZCuPsdaYMVBq~$zPaMHgJD_eOPCe6N-{(gGQ%t0Dk z_@I$P27p$?b^VObTSr!iQeeRuvGpGf#}onTmIAIKA%LB^Z>I*-?SBy%8U96$@uaai zM)M%NQnd-MW;3a}!4_Whzle1#FJhKzJ_{cqxe#_I>B(T zVQAPav*E;ac7bc>R2HLuF+!t!{#iDqtu@yvxX-xJ!-JX`;@=3} zwd5!Y&Z9x1i^?{?WsPkU0?-C z&oWC+t}6G9{BaF$1m6s_tKk;}^t_SWHd)ljknyDJYMiD!26zT!5;&32s!{}B{iB_r z{T(FjrnW|w7YYIn=%k!pw`Ae86k;uS*X$J!fwN~^wlE^J3gJSSE6m0$`}cJrYR{;; zgbPU~+yXTT@Dk+*Q){;k9!bgf@~HQ*?i!Z5f4 zGRzj!ST#IXpwY48n-VD~H$94hP$|OPyW2b5%#59QeLqXgAdujszsX9eV)4|)E_)nfHJheBnG6xdQ)00Y)ThEocf zVAW#`zJ?3G2a>CG6LO+}vVuLAzA`zDS%}5?bv;Aj01%av7eaz*U>9UDx58G(xv1i!eXK18A?tP^A1L?`i22GilJIH%3Dq9?wPrp zQMsw8Uu^U><=~k`#4D!(>XcqwF?{r*Y@J*Bwv6RJ0A;{X(~*`ijW%T4Dmk??Gjz<`f!bC364JIOa0XC9`&s-`gE=>Pt@~?|liMY)lR+XM=&_ zY9ZI%T=1OoacqoV_}oe6*?(v8UEW`N?z~0?1*$y|+z2DEh8&nTu)M5AyPMFcw$EnO z8uF|LzU1XE*dhza=WgRKX+FK{56TW!rXjw^lw4yqkLl9flAhvc3Y(%>5BfV1sBW{; zGOw}7`rD6Pp|k;Nu)Yvz=7#qWcE?}$?6Bc@sGN3=yDX-&M;&?Jv}u*sy4WRgrwp-5K#IgAc|f-4|?OCFcSpNAgB~A{g;%@$aMTWzZ%0}^L4o+BLCgUa+3*FLan>r zP(5Hb4&MSkS6X_U_gJ`#M(+KuY~seLPQS9hayhn%k~bEwY{OO{bZ$)Y02z0pV(Tx= z6d7c}B$kM?2i$MdZCYlLq>r42jPiU#Z>jN8x0AR9Qxe2J8fS{b{3}+ncg&dDT~J{c zO8;&A26C%a5*HH-1i8Vtaao#k*ESBYT|MZ3u5Wyf^Wq$d{j+gR$p z8V!nK?XU96;Gng;ZE6T!X<3$V;&e^Ey8h?Ajpmgi7tJ8xjx1xo=zd;hol+I6@e+5ub2s?-%cV*b{}%Q^movs>Nt?wv zmNq@fFfttCOe`9vw7)_$(*6)CmMc9c4ZW63Zi;yomsnl(w*jXmaXA!gX-%KUE*8cy zw@2$;o6&-M<5fUdi}pbK6?iun&R0b|nZ;M}<>=vFRVo=$qX?pf#j0nPc(u#;(zifM{VZRlX^`FLFQ2 zY`*ChE_yp&2mcOnKs|8~3>xpif@P%X6*ncj zr~L}DoHH(NVKT59qH_RHbE5?b~cDI%P@zN23l!A1~Xqz z<=i?zgy^ei`11f3xrvcaAZ7V8UIfGvMjbg;0^%KvUaqU#k-joeOFYfr3In5dn!M-z zD!{SyNg9PoCQGr`?pio=2B`S==7rGi71*u|>WVsXi{(ZOqXq5RNvuPJR~4A&Yb2bJ z&FpcksRs*|mNwM7b_&pQC>>Tw_wT|3kD~6*zZTx`m<;%v976LRQh^5FOeN=*8!6y) z8LWt!jET=~?Fxf*2V;9Gfmorzp50(F-X;=v(4yj7<+rDoEslmby47Gw?wwDQ{z&Iu za8~!SL`0z(bK_j%NZg|#C8EQx52l&9$;$+zAi)x{@H7AkLxkGvP`FY5+wcxdbFiB}AhR6K#}n zSG&?38TPBjZBb037dj$sr(6p?sy}cO>oTH-SvsH3AU+8xtd5OooDm?SL^?8?X7)_{ z$bxRgsA)IkJRcI|N7Q>DQ;ZR-fk?g(&o}9mcjkY*bhfOD$dBkb7am*j1a7bDi6kY- zy?2|px_J5?$YXP)mwi*Imtwmc(cP6bfB}1F9Fs^TAjEcSUJj`!xj>&GfJ?Nme12~1 zXR(h~3gc}sQk!TMRQdh>{IAaBT;ul~rasMu*pXhaii#GYRUPpf;Lo+NyxI2l!9ceA&Vk zzWo8}CpuljR)+~RHA6=WYIGaZU_>Gpc;LKc(v3)uKE0lba8cuAaSV^z0A-xa6eloA zR{?Now)WA~2UT6CA06*3XdoGKB-F*$)`0ODZ!`Dfd-lQOhk)b2m;CMpX@KyX-r*}h zE04Xwi6-4Hau~+Ze?IhQ z4>6|%+LWThVbaqja%}Gf>dKj3E=3_jSLU#P`S&b>eg&fdpY_7?FP=AjJRBYKC6_ z-mrXD!!8XvOqLl!r3boUr<1SR4FBP#Z(t?uGKK{>lr=dE!{Q`pPDN2S`d4zjAMdFy z6|Dg!RE|$RC$jc28ZDXgtE>oB;HQsZJ_Ic{-k&`!dFONMRSpcf6_>fq>wOmA(uwmN z9`*TxS4q79Br0Qs=!h>lX}vlb8TN%81|CtL81&bBIZ#DaCVsA5(_r4n@KRl-9&k>7_5L^fB0TuaNxiMA zG`EVu);{3yy*d}sZYFwnrV~5Mfp+*N=k)XnA{QTcTXjN91;WlN2X~bF_Sm!wozdKr zQnn|(sWHx;yBp%RvYff85efD`>-9cHYGN)^tIkxv4f82CT|kB^rt0g9L-Axzj39yI zX2|@9`P&Qf%zfG3C(N(ZMTm2Yq|P>SpG;V(Fz(r|G+qMsO?QX-S4~pb7$5e7~D#ow!Sc zm|pQ)A~R&Sea>jpTxW8c;)<<@I3u8Ad3|W*lll|ptjTg8tvXQy4qhLwUjwn&joT*A z1HO_O;55bs{yaVUKAcHQWFt3wnAwEHF~2z?!8IdX+n+RRE3PCcIes*`u@czX-tpyd zA?)6BZppPywn@I`WsFP~0jZ+0HS$5cw=x4zv`3>c@8Pw(4{rX+7Y@1$+{hzA8x?UT z^1Mdqi5ehxG)TVSV<(9pl}gSWvYydae>{mJwJ59O)l~`#nmZ+$yKDh)mn=REX-8LH<&7 zREHEoR4))=yv11PG}wk~gCA!#e7!~EwKFg|dT^y7mA1`I;)6E;i8b7XJTg=ePI!V# z(JmzxK5iN8d?_G_fQ=_@PbCmf@l=E}r@rEGPZbFy3pR(VN_n_ttfwUn735wz6b~q*6mho57@_$BO)8E5^5~Hy$ClvLUF8R z@>3N2-l)rSrgHDtONRY-ZwO!IIl$djx}0xJ__8ozhU8wz_awJsAqXb{n_+FaFLQVI zSMI#2CoukYH3t*>zmZ1c9XQGG`CSHM3T)ZO)J=6sEET-YH%4YZGy?l^7#3{O>{&6I zZD+3U%Zx4MrhW9ePq9~RqNEGdvSo}#3jw3+4jKtlX@!N1*mR8)jHDPZT!nm!66>Xd z54JDDFacsOYIo)yyXM3TG=Z?D@reOB`CYWaNa z-RdcCl_--EfgWrR5Inv}PNRV&z|X^3w$yAZDO3+R z_2Td{9J_h|>QUqOo#3qws{O|;?|5fjms`1;64HN><8Ho34sYHo`6u}^qyfIe0$i+0 zL;lB5EXsNd$)y;qc`G!)8b`2Iv^9!e^M4y!KX#7Jf9XOf;=PAK0uwLAB1%}?PV zH)Hk!pOo>6!a>Zkns#bjO={#3LqO$j;H|)-6Ri=}SKY9Q3v;cu3bxv0s|Q1bE#D{L zR7Zb$Y5z|XCqdV)&o>XZ4xyi@JdEF@2N2hnD-p=>3Hw(jJt{LCs zQiykz2qCEg%~1Xt5>7>%;l&O)VO3r?e|wTWCM44&x{5gx?V85Phr-8Db(Oue=r@q* zjpGl`o}yMqQ5`xzTtDV!-IMKZb%Kh%i+(ZwM#5778y!gfus+vXQ|5iDZj;u`RFn#m2i@u_chNln-TzB_?v&%r^*By6?m)$=5;@CpcF%r zA0IrrAy2sQY-`dtbMq|HOEj(A4YaPJ%{8YQxObk+;FaQ>!aB_y$hs9xxcfMPVrRP0 z#=f%F2~6|r{cRnmiAMTjvyA+>@`XlJWbGVwN4M+^yX)L2YzKVP;-p z3#SQA0`W`YQ?NWZ7`=96BqH;M))3O2TZQv=0_e@@0fykSYR_{|CW5p0YRcJ+6c`NJTI$RA+>kd>4kfj6=2v7ux(E8rW<+d-AVOOj-jh*$P!aDDT=BJC~Lx=(LLe&-sip?+VM z>jHQ~mmPkn3|R7tH*tL(Ib*uOYg~{*tLL#S(ksO zn|mW0`*tT9_qWTFhGD3k8K8nh?kAC1fWTtAvp;%p*=Xb=SJ*tIjp(7S{p%x}ErLTJ z4`3eiEy+8@@15vdpfPPo1)Zan@}JSlfEK>o-t}l_gY5=~FB?5$|J=Q(rEhm|FIuXW zZGH>pR-%FD?KTxQisAC`KB#VBv2MRtpRCrE2NYo_T^K#v8wiAH?ZV=ztGdCT7{&o= zxlxhvc&nQ~R>m<pezrZc^!;OJn?+gU(CV#**Rg;@ydad z9F*&W2c2~%v-wBk{RS7*>3%j%&w1ICBHhF*aw!9k)Ep)uQ8y5ZlxDV$1Io=!Xr;W3(d9Ee zNN&zQDH=Bnjy;O=5cn8;C;FU|1mw{gkczu(;_ph}!R(X^#QKBp1MS)5oD4*I;su5% zbFbDQc5n{DEyyLedXmWeVvo^Ut#w%no_~`^&BE`u?TRC@O6C3S&>W{7_x5_Y1-(21 zd{poq78NRrxAxF(4inW?gPT$#IAYZ?X@}*y;ElIYuVE&H;A6no@axfQW`9WD8@1r? zifP&jJo~B~&l~=?3g)JoY&UOd8&yi|TD4zozw_r2ZFB}KsJq@iFp<^S=a;}tq|e1i zM?^B33wuC5P}=pCvu+$&PvInp+*gArF^UP6yTtm4>3hBeqIG&N_=ruRq%pKI#Mo~2 zQepn*+631L|7}biqwA?~L$54J7te!WNDF_$^IKQ|ZS*(#QD1EGvE2j!b|`SYNe}ny zOo2OdfTEsZ09GxJr%I~Ucyx!vkDadt&TXK=B16J^i48NP&i5?tiUV-Yt}PYNcd*X? zs4hxRXn)OW#&$QnC!5zIw=xf66smN1nqnvLPjfHWp-Bh%yY;JE6?~HS`q-i8FJ0`Z z8hS;9{2NXC1y6W(M(3AIX#OETj<6@@-Y@kj(AAA+(>thRWFBgE#%nZnOe`AvNwWow z`4lgWctk`CU26AhEs>>Iw=D0k^35NG@Z(73W=xS&Kmuj?Nfgeeu(EN=u%ylPgl%W&}Ts9pHq6L;5_h7_19ZRVFIW1>@q z=rCpNSnYBrK}%waU<)hzr1?@DSA857FVPBEczt-BZ@?jv?=dr&tpy}57@?on@d$g{r;#MLf7pwERxcGy~=Kq>p?zl=*Ip- z=mF&Zczs;>&tjXdIt8}6@$2X&_ow?ARy*Kyh`_yIFl0C)@Tr}rydDl9QyM$NV;2#(<)i*dtWJ*9~f_8jDXKZ4t$tDc9uLi$J};Y(i`&V?Yj zAGARMJAoxA)ZYPE%|!`2VFVT$PdX61%Q%@!7%#z{jz1kG_l=^i0z*ihjm&2E^9;=z zZv$@k{l}36)h^kU0^rue+IX7thY0(z5XmgARe1I-(USXLHFti%0w=*~o!#~lA^9c$HQ}j7n2V-2!@UqU^DD* z+%3`j8e=!z8IOm0q&uo|8AlUdLR;22P7ndEwq`Q&8C$vh<}=jZj%E@S6T9Z5QO56D zc4}^rJC0Eo${x`rub=Jptt0mG2xw^u>cdfV{{#+58YnpJukqTgS|vJe!~^@F~raMP?1UhUW1(5z?Ro(4M^gW zPU)*-eV{U6cUgceO@W0fKsvNTmXb!bV9o%kSzmY&S{UCR6p}dL?1fG4@BbCWP}o zKoeZQ-9!#G?1tf7y2W8gjS!wMoIO|(s}ts;&N&BW(~dYn zGapS-|MI5vUX>k#X)MZJ>hY4VS><9r>hCX^%qaGVw{>G_U zbhnzjyJk|#qX@0$%@Q>Bj5Vgkrh1YRMKsIB3}apd516c*E676Q+({{sFbkq0vhQ&J zHSt4K2e}>&6Dr&|4iDC0f(%XY{S6@oo5dua3FwW%U4Kg}n8KD2(UunRNUKq5LE`c+ z+wItZ=_TVd$S=|f(Qce%DE*LZ$bydc9aF>)?4X_zA~#nB(vPdnr#YQ%x<*VG!=85^ zSJe3sb71|-l(l@B#pqNuf(V@xmH>il43;4rc=G+~IqT0y2B`6?oV8>&{#BCCZzmd_ z+tL10i241z`+or6)rAM)B9iNMlT7f%(v~SfT}ffrE)^)bFeNgD#tgiUpMyjWsuqa6 z;jeDFWHS$*Uw=0DpIfhZ+~w~)*}n`aUsFg8QA+izeMEKHzYzZ8#5>d3lYjrWZ_@IzI)D&fa=gQxCrlPuD9 zA3oLJ82b;$s#(7a6#HKHTA4!p5maf^Fc`r;aiQ+;S&^Kw zfupguQJzp|#-_1{`{_TPhXKO3wU^-w3M3$UG^~15;mYOH61;AICusJUxaO`1pa_b> zz3vOWxjF20l$=75LQRE842Sy?GG5ULXf)Ct=A_x*s6`3Ar3@V>{6SvfRW+Z!0duIU zu-)}_Rk%vz<~es~lar_m@I2Me)Rdo0<%xN35KMQSgTK|=m(wz@qrUCPpEMS{`Jr!b zPE_?gyEPAEZ{9{*O6qoygXwc+^LNv8v^|?(e(w|L1ZU?8%t16}*p-56hUbzI7USLchbh#~%Lb zdS|mI1gdx3`R{me-s$IY6=dH#a~Ntw4jmQq{weIa8!HVI4QRCC;J?OiF8e>BirMr) z5CAqW7gC!|tYZ_essRyIp`1%72-u*aW);9`9txRMu1xZ@A=OHg^dmNVAuf;X&+`wW zx8Y!B-+%o9&esi6Q<>G}uw4@!5BJ=^kA;Mvn6wph*ZF&j-6!24;|Klf7GNE%%u8yC zT9{tb0-_zlWA%#gbhinp53M@qSkgTht?*@(twmzorj-=kGH>*J_8Vyy48ToNE7q3|6dW*GE83S?V; literal 0 HcmV?d00001 diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts index 1f0bae8933..d442eaefe7 100644 --- a/packages/neuron-wallet/src/controllers/api.ts +++ b/packages/neuron-wallet/src/controllers/api.ts @@ -926,7 +926,7 @@ export default class ApiController { params: { outPoints: OutPoint[] locked: boolean - password: string + password?: string lockScripts: CKBComponents.Script[] } ) => { diff --git a/packages/neuron-wallet/src/controllers/cell-management.ts b/packages/neuron-wallet/src/controllers/cell-management.ts index 690de0d4c7..4e0ee8ce20 100644 --- a/packages/neuron-wallet/src/controllers/cell-management.ts +++ b/packages/neuron-wallet/src/controllers/cell-management.ts @@ -61,7 +61,7 @@ export default class CellManagement { outPoints: OutPointSDK[], locked: boolean, lockScripts: Script[], - password: string + password: string = '' ) { // check wallet password const currentWallet = WalletService.getInstance().getCurrent() @@ -69,7 +69,7 @@ export default class CellManagement { const addresses = new Set((await AddressService.getAddressesByWalletId(currentWallet.id)).map(v => v.address)) const isMainnet = NetworksService.getInstance().isMainnet() if (!lockScripts.every(v => addresses.has(scriptToAddress(v, isMainnet)))) throw new AddressNotFound() - await SignMessage.sign(currentWallet.id, scriptToAddress(lockScripts[0], isMainnet), password, 'verify password') + await SignMessage.sign(currentWallet.id, scriptToAddress(lockScripts[0], isMainnet), password, 'verify cell owner') return CellLocalInfoService.updateLiveCellLockStatus(outPoints, locked) } From 32fac325928b2bbe9f9a3dec7688d80ef3928d6b Mon Sep 17 00:00:00 2001 From: yanguoyu <841185308@qq.com> Date: Wed, 13 Mar 2024 11:35:20 +0800 Subject: [PATCH 2/2] fix: Add tx hash for cell info dialog --- .../CellInfoDialog/cellInfoDialog.module.scss | 6 ++++ .../src/components/CellInfoDialog/index.tsx | 34 ++++++++++++++++-- .../src/components/CellManagement/hooks.ts | 35 +++++++++++-------- .../src/components/CellManagement/index.tsx | 7 +++- .../components/HistoryDetailPage/index.tsx | 2 +- packages/neuron-ui/src/locales/en.json | 1 + packages/neuron-ui/src/locales/es.json | 1 + packages/neuron-ui/src/locales/fr.json | 1 + packages/neuron-ui/src/locales/zh-tw.json | 1 + packages/neuron-ui/src/locales/zh.json | 1 + .../tests/controllers/cell-management.test.ts | 2 +- 11 files changed, 71 insertions(+), 20 deletions(-) diff --git a/packages/neuron-ui/src/components/CellInfoDialog/cellInfoDialog.module.scss b/packages/neuron-ui/src/components/CellInfoDialog/cellInfoDialog.module.scss index 148d7b4f99..1831f13f93 100644 --- a/packages/neuron-ui/src/components/CellInfoDialog/cellInfoDialog.module.scss +++ b/packages/neuron-ui/src/components/CellInfoDialog/cellInfoDialog.module.scss @@ -1,3 +1,5 @@ +@import '../../styles/mixin.scss'; + .cellInfoDialog { min-width: 650px; } @@ -270,3 +272,7 @@ top: 4px; cursor: pointer; } + +.notice { + @include dialog-copy-animation; +} diff --git a/packages/neuron-ui/src/components/CellInfoDialog/index.tsx b/packages/neuron-ui/src/components/CellInfoDialog/index.tsx index 20bc08a669..e75da3363a 100644 --- a/packages/neuron-ui/src/components/CellInfoDialog/index.tsx +++ b/packages/neuron-ui/src/components/CellInfoDialog/index.tsx @@ -1,11 +1,14 @@ -import React, { useMemo, useState } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import Dialog from 'widgets/Dialog' -import { calculateUsedCapacity, shannonToCKBFormatter } from 'utils' +import { calculateUsedCapacity, getExplorerUrl, shannonToCKBFormatter, truncateMiddle, useCopy } from 'utils' import { useTranslation } from 'react-i18next' import Tabs from 'widgets/Tabs' import { type TFunction } from 'i18next' import { Script } from '@ckb-lumos/base' import Switch from 'widgets/Switch' +import { Copy, ExplorerIcon } from 'widgets/Icons/icon' +import Alert from 'widgets/Alert' +import { openExternal } from 'services/remote' import styles from './cellInfoDialog.module.scss' type ScriptRenderType = 'table' | 'raw' @@ -108,13 +111,26 @@ const useTabs = ({ t, output }: { t: TFunction; output?: State.DetailedOutput }) } } -const CellInfoDialog = ({ onCancel, output }: { onCancel: () => void; output?: State.DetailedOutput }) => { +const CellInfoDialog = ({ + onCancel, + output, + isMainnet, +}: { + onCancel: () => void + output?: State.DetailedOutput + isMainnet: boolean +}) => { const [t] = useTranslation() const { tabs, currentTab, setCurrentTab, scriptRenderType, setScriptRenderType } = useTabs({ t, output, }) + const { copied, copyTimes, onCopy } = useCopy() + const onOpenTx = useCallback(() => { + const explorerUrl = getExplorerUrl(isMainnet) + openExternal(`${explorerUrl}/transaction/${output?.outPoint.txHash}`) + }, [isMainnet, output?.outPoint.txHash]) if (!output) { return null } @@ -124,6 +140,13 @@ const CellInfoDialog = ({ onCancel, output }: { onCancel: () => void; output?: S title={
{t('cell-manage.cell-detail-dialog.title')} +
+ {t('cell-manage.cell-detail-dialog.transaction-hash')} + :   + {truncateMiddle(output.outPoint.txHash, 10, 10)} + onCopy(output.outPoint.txHash)} /> + +
} onCancel={onCancel} @@ -149,6 +172,11 @@ const CellInfoDialog = ({ onCancel, output }: { onCancel: () => void; output?: S ) : null} + {copied ? ( + + {t('common.copied')} + + ) : null}
) } diff --git a/packages/neuron-ui/src/components/CellManagement/hooks.ts b/packages/neuron-ui/src/components/CellManagement/hooks.ts index 32ec3904a2..e38c6cec29 100644 --- a/packages/neuron-ui/src/components/CellManagement/hooks.ts +++ b/packages/neuron-ui/src/components/CellManagement/hooks.ts @@ -380,12 +380,10 @@ export const useHardWallet = ({ wallet, t }: { wallet: State.WalletIdentity; t: const isWin32 = useMemo(() => { return getPlatform() === 'win32' }, []) - const [error, setError] = useState() - const disconnectStatus = t('hardware-verify-address.status.disconnect') - const ckbAppNotFoundStatus = t(CkbAppNotFoundException.message) + const [error, setError] = useState() const isNotAvailable = useMemo(() => { - return error === disconnectStatus || error === ckbAppNotFoundStatus - }, [error, disconnectStatus, ckbAppNotFoundStatus]) + return error === ErrorCode.DeviceNotFound || error === ErrorCode.CkbAppNotFound + }, [error]) const [deviceInfo, setDeviceInfo] = useState(wallet.device) const [isReconnecting, setIsReconnecting] = useState(false) @@ -436,15 +434,13 @@ export const useHardWallet = ({ wallet, t }: { wallet: State.WalletIdentity; t: setError(undefined) return true } catch (err) { - if (err instanceof CkbAppNotFoundException) { - setError(ckbAppNotFoundStatus) - } else { - setError(disconnectStatus) + if (err instanceof CkbAppNotFoundException || err instanceof DeviceNotFoundException) { + setError(err.code) } return false } }, - [disconnectStatus, ckbAppNotFoundStatus, isWin32] + [isWin32] ) const reconnect = useCallback(async () => { @@ -464,14 +460,14 @@ export const useHardWallet = ({ wallet, t }: { wallet: State.WalletIdentity; t: } await ensureDeviceAvailable(device) } else { - setError(disconnectStatus) + setError(ErrorCode.DeviceNotFound) } } catch (err) { - setError(disconnectStatus) + setError(ErrorCode.DeviceNotFound) } finally { setIsReconnecting(false) } - }, [deviceInfo, disconnectStatus, ensureDeviceAvailable, wallet.id]) + }, [deviceInfo, ensureDeviceAvailable, wallet.id]) const verifyDeviceStatus = useCallback(async () => { if (deviceInfo) { @@ -479,13 +475,24 @@ export const useHardWallet = ({ wallet, t }: { wallet: State.WalletIdentity; t: } return true }, [ensureDeviceAvailable, deviceInfo]) + + const errorMessage = useMemo(() => { + switch (error) { + case ErrorCode.DeviceNotFound: + return t('hardware-verify-address.status.disconnect') + case ErrorCode.CkbAppNotFound: + return t(CkbAppNotFoundException.message) + default: + return error + } + }, [error, t]) return { deviceInfo, isReconnecting, isNotAvailable, reconnect, verifyDeviceStatus, - error, + errorMessage, setError, } } diff --git a/packages/neuron-ui/src/components/CellManagement/index.tsx b/packages/neuron-ui/src/components/CellManagement/index.tsx index 864edd3f62..48f94566e2 100644 --- a/packages/neuron-ui/src/components/CellManagement/index.tsx +++ b/packages/neuron-ui/src/components/CellManagement/index.tsx @@ -13,6 +13,7 @@ import { outPointToStr, LockScriptCategory, getLockTimestamp, + isMainnet as isMainnetUtil, } from 'utils' import { HIDE_BALANCE } from 'utils/const' import Tooltip from 'widgets/Tooltip' @@ -220,8 +221,11 @@ const CellManagement = () => { wallet, chain: { syncState: { bestKnownBlockTimestamp }, + networkID, }, + settings: { networks }, } = useGlobalState() + const isMainnet = useMemo(() => isMainnetUtil(networks, networkID), [networks, networkID]) const [t] = useTranslation() const [searchParams] = useSearchParams() const breadPages = useMemo(() => [{ label: t('cell-manage.title') }], [t]) @@ -244,7 +248,7 @@ const CellManagement = () => { isNotAvailable, reconnect, verifyDeviceStatus, - error: hardwalletError, + errorMessage: hardwalletError, setError: setHardwalletError, } = useHardWallet({ wallet, @@ -344,6 +348,7 @@ const CellManagement = () => { : undefined } onCancel={onActionCancel} + isMainnet={isMainnet} /> {wallet.device ? ( { type="failed" onCancel={() => navigate(-1)} /> - + ) } diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index ac7c253bde..c42810c3f5 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -1198,6 +1198,7 @@ }, "cell-detail-dialog": { "title": "Cell Detail", + "transaction-hash": "Transaction Hash", "capacity-used": "Used Capacity", "data": "Data", "total": "Total", diff --git a/packages/neuron-ui/src/locales/es.json b/packages/neuron-ui/src/locales/es.json index 4c7aca25cc..8d38510953 100644 --- a/packages/neuron-ui/src/locales/es.json +++ b/packages/neuron-ui/src/locales/es.json @@ -1177,6 +1177,7 @@ }, "cell-detail-dialog": { "title": "Detalles de la Cell", + "transaction-hash": "Hash de Transacción", "capacity-used": "Capacidad utilizada", "data": "Datos", "total": "Total", diff --git a/packages/neuron-ui/src/locales/fr.json b/packages/neuron-ui/src/locales/fr.json index 3be32a2e72..5cd1baf641 100644 --- a/packages/neuron-ui/src/locales/fr.json +++ b/packages/neuron-ui/src/locales/fr.json @@ -1188,6 +1188,7 @@ }, "cell-detail-dialog": { "title": "Détail de la cellule", + "transaction-hash": "Hash de transaction", "capacity-used": "Capacité utilisée", "data": "Données", "total": "Total", diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json index 922264bc0d..0208b9e9d4 100644 --- a/packages/neuron-ui/src/locales/zh-tw.json +++ b/packages/neuron-ui/src/locales/zh-tw.json @@ -1169,6 +1169,7 @@ }, "cell-detail-dialog": { "title": "Cell詳情", + "transaction-hash": "交易哈希", "capacity-used": "容量使用", "data": "數據", "total": "總量", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index 958956b672..fbb85cf7af 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -1190,6 +1190,7 @@ }, "cell-detail-dialog": { "title": "Cell详情", + "transaction-hash": "交易哈希", "capacity-used": "容量使用", "data": "数据", "total": "总量", diff --git a/packages/neuron-wallet/tests/controllers/cell-management.test.ts b/packages/neuron-wallet/tests/controllers/cell-management.test.ts index e1ad5a0623..eb5a357e29 100644 --- a/packages/neuron-wallet/tests/controllers/cell-management.test.ts +++ b/packages/neuron-wallet/tests/controllers/cell-management.test.ts @@ -155,7 +155,7 @@ describe('CellManage', () => { getAddressesByWalletIdMock.mockResolvedValueOnce([{ address }]) const outPoints = [new OutPoint(`0x${'00'.repeat(32)}`, '0')] await CellManagement.updateLiveCellsLockStatus(outPoints, true, [lockScript], 'password') - expect(signMock).toBeCalledWith('walletId1', address, 'password', 'verify password') + expect(signMock).toBeCalledWith('walletId1', address, 'password', 'verify cell owner') expect(updateLiveCellLockStatusMock).toBeCalledWith(outPoints, true) }) })