Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion packages/neuron-ui/src/components/SUDTSend/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Button from 'widgets/Button'
import Spinner from 'widgets/Spinner'
import { ReactComponent as TooltipIcon } from 'widgets/Icons/Tooltip.svg'
import { ReactComponent as Attention } from 'widgets/Icons/Attention.svg'
import { ReactComponent as WarningAttention } from 'widgets/Icons/ExperimentalAttention.svg'
import { getSUDTAccount, destoryAssetAccount } from 'services/remote'
import { useState as useGlobalState, useDispatch, AppActions } from 'states'
import {
Expand All @@ -29,7 +30,15 @@ import {
} from 'utils'
import { AmountNotEnoughException, isErrorWithI18n } from 'exceptions'
import { UANTokenName, UANTonkenSymbol } from 'components/UANDisplay'
import { AddressLockType, getGenerator, useAddressLockType, useOnSumbit, useOptions, useSendType } from './hooks'
import {
AddressLockType,
SendType,
getGenerator,
useAddressLockType,
useOnSumbit,
useOptions,
useSendType,
} from './hooks'
import styles from './sUDTSend.module.scss'

const { INIT_SEND_PRICE, DEFAULT_SUDT_FIELDS } = CONSTANTS
Expand Down Expand Up @@ -405,6 +414,12 @@ const SUDTSend = () => {
<TooltipIcon width={12} height={12} />
</span>
) : null}
{(v.key === SendType.secp256Cheque && !isMainnet) ? (
<div className={styles.chequeWarning}>
<WarningAttention />
{t('messages.light-client-cheque-warning')}
</div>
) : null}
</div>
))}
{!isOptionCorrect && <div className={styles.selectError}>{t('s-udt.send.select-option')}</div>}
Expand Down
14 changes: 14 additions & 0 deletions packages/neuron-ui/src/components/SUDTSend/sUDTSend.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,20 @@
}
}
}

.chequeWarning {
padding: 0 8px;
margin-left: 8px;
background-color: rgb(255, 244, 206);
color: rgb(50, 49, 48);

& > svg {
width: 14px;
height: 14px;
margin-right: 4px;
transform: translateY(20%);
}
}
}
.cheque {
grid-area: option-0;
Expand Down
1 change: 1 addition & 0 deletions packages/neuron-ui/src/components/Send/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ const Send = () => {
onSendMaxClick={handleSendMaxClick}
onLocktimeClick={handleLocktimeClick}
isTimeLockable={!device}
isMainnet={isMainnet}
/>
)
}}
Expand Down
4 changes: 3 additions & 1 deletion packages/neuron-ui/src/components/SendFieldset/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface SendSubformProps {
onLocktimeClick?: React.EventHandler<React.SyntheticEvent<HTMLButtonElement>>
onSendMaxClick?: React.EventHandler<React.SyntheticEvent<HTMLButtonElement>>
onItemChange: React.EventHandler<React.SyntheticEvent<HTMLInputElement>>
isMainnet: boolean
}

const SendFieldset = ({
Expand All @@ -54,6 +55,7 @@ const SendFieldset = ({
onSendMaxClick,
onItemChange,
isTimeLockable = true,
isMainnet,
}: SendSubformProps) => {
const [t] = useTranslation()

Expand Down Expand Up @@ -162,7 +164,7 @@ const SendFieldset = ({
{item.date && (
<div className={styles.locktimeWarn}>
<Attention />
{t('send.locktime-warning')}
{t('send.locktime-warning', { extraNote: isMainnet ? null : t('messages.light-client-locktime-warning') })}
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const SendFromMultisigDialog = ({
onOutputRemove={deleteSendInfo}
onItemChange={onSendInfoChange}
onSendMaxClick={onSendMaxClick}
isMainnet={isMainnet}
/>
))}
</div>
Expand Down
4 changes: 3 additions & 1 deletion packages/neuron-ui/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@
"set-locktime": "Set Locktime",
"locktime-notice-content": "According to the actual running block height, there may be some time variances in locktime.",
"release-on": "Release on",
"locktime-warning": "Please ensure that receiver's wallet can support expiration unlocking. In general, exchanges do not support expiration unlocking, please use with caution!"
"locktime-warning": "Please ensure that receiver's wallet can support expiration unlocking. (Note: 1.Exchanges generally do not support expiration unlocking {{extraNote}})"
},
"receive": {
"title": "Receive",
Expand Down Expand Up @@ -509,6 +509,8 @@
"rebuild-sync": "For better user experience, Neuron has adopted a new storage, which requires a migrating of data (estimated 20 ~ 60min).\nSorry for the inconvenience.",
"migrate": "Migrate",
"secp256k1/blake160-address-required": "Secp256k1/blake160 address is required",
"light-client-locktime-warning": "2.Light client mode doesn't support showing lock-time CKBytes.",
"light-client-cheque-warning": "Warning: Light client mode doesn't support showing Cheque assets.",
"fields": {
"wallet": "Wallet",
"name": "Name",
Expand Down
4 changes: 3 additions & 1 deletion packages/neuron-ui/src/locales/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@
"set-locktime": "設置鎖定時間",
"locktime-notice-content": "鎖定時間根據區塊鏈實際運行情況會有一定的誤差。",
"release-on": "鎖定至",
"locktime-warning": "請確保對方錢包能夠支持到期解鎖功能。一般情況下,交易所不支持到期解鎖功能,請謹慎使用!"
"locktime-warning": "請確保對方錢包支持到期解鎖功能。(註:1.交易所壹般不支持到期解鎖功能 {{extraNote}})"
},
"receive": {
"title": "收款",
Expand Down Expand Up @@ -501,6 +501,8 @@
"rebuild-sync": "為了提供更好的用戶體驗,Neuron 採取了新的存儲方案,該方案需要壹次性遷移數據(預期同步時間為 20~60 分鐘)。\n抱歉給您帶來不便。",
"migrate": "遷移",
"secp256k1/blake160-address-required": "請輸入 secp256k1/blake160 地址",
"light-client-locktime-warning": "2.輕節點模式不支持展示到期解鎖的 CKBytes。",
"light-client-cheque-warning": "註意: 輕節點模式不支持展示 Cheque 資產。",
"fields": {
"wallet": "錢包",
"name": "名稱",
Expand Down
4 changes: 3 additions & 1 deletion packages/neuron-ui/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@
"set-locktime": "设置锁定时间",
"locktime-notice-content": "锁定时间根据区块链实际运行情况会有一定的误差。",
"release-on": "锁定至",
"locktime-warning": "请确保对方钱包能够支持到期解锁功能。一般情况下,交易所不支持到期解锁功能,请谨慎使用!"
"locktime-warning": "请确保对方钱包支持到期解锁功能。(注:1.交易所一般不支持到期解锁功能 {{extraNote}})"
},
"receive": {
"title": "收款",
Expand Down Expand Up @@ -502,6 +502,8 @@
"rebuild-sync": "为了提供更好的用户体验,Neuron 採取了新的存储方案,该方案需要一次性迁移数据(预期同步时间为 20~60 分钟)。\n抱歉给您带来不便。",
"migrate": "迁移",
"secp256k1/blake160-address-required": "请输入 secp256k1/blake160 地址",
"light-client-locktime-warning": "2.轻节点模式不支持展示到期解锁的 CKBytes。",
"light-client-cheque-warning": "注意: 轻节点模式不支持展示 Cheque 资产。",
"fields": {
"wallet": "钱包",
"name": "名称",
Expand Down
1 change: 1 addition & 0 deletions packages/neuron-ui/src/stories/SendFieldset.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ stories.add('Common', () => {
onItemChange: (e: any) => action('Item Change')(JSON.stringify(e.target.dataset), e.target.value),
onScan: () => action('Scan'),
onSendMaxClick: (e: any) => action('Click Send Max button')(JSON.stringify(e.target.dataset)),
isMainnet: false
}
return <SendFieldset {...props} />
})
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ const useGetCountDownAndFeeRateStats = ({ seconds = 30, interval = 1000 }: Count
(stateDispatch: StateDispatch) => {
getFeeRateStats()
.then(res => {
const { mean, median } = res
const suggested = mean && median ? Math.max(1000, Number(mean), Number(median)) : MEDIUM_FEE_RATE

setFeeFatestatsData(states => ({ ...states, ...res, suggestFeeRate: suggested }))
if (res) {
const { mean, median } = res
const suggested = mean && median ? Math.max(1000, Number(mean), Number(median)) : MEDIUM_FEE_RATE

setFeeFatestatsData(states => ({ ...states, ...res, suggestFeeRate: suggested }))
}
})
.catch((err: Error) => {
try {
Expand Down
2 changes: 1 addition & 1 deletion packages/neuron-wallet/electron-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ afterSign: scripts/notarize.js
files:
- from: "../.."
to: "."
filter: ["!**/*", ".ckb-version", "ormconfig.json"]
filter: ["!**/*", ".ckb-version", ".ckb-light-version", "ormconfig.json"]
- package.json
- dist
- ".env"
Expand Down
25 changes: 17 additions & 8 deletions packages/neuron-wallet/src/controllers/app/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,28 @@ const separator: MenuItemConstructorOptions = {
type: 'separator'
}

const showAbout = () => {
let applicationVersion = t('about.app-version', { name: app.name, version: app.getVersion() })

const appPath = app.isPackaged ? app.getAppPath() : path.join(__dirname, '../../../../..')
const ckbVersionPath = path.join(appPath, '.ckb-version')
if (fs.existsSync(ckbVersionPath)) {
const getVerionFromFile = (filePath: string) => {
if (fs.existsSync(filePath)) {
try {
const ckbVersion = fs.readFileSync(ckbVersionPath, 'utf8')
applicationVersion += `\n${t('about.ckb-client-version', { version: ckbVersion })}`
return fs.readFileSync(filePath, 'utf8')
} catch (err) {
logger.error(`[Menu]: `, err)
}
}
}

const showAbout = () => {
let applicationVersion = t('about.app-version', { name: app.name, version: app.getVersion() })

const appPath = app.isPackaged ? app.getAppPath() : path.join(__dirname, '../../../../..')
const ckbVersion = getVerionFromFile(path.join(appPath, '.ckb-version'))
if (ckbVersion) {
applicationVersion += `\n${t('about.ckb-client-version', { version: ckbVersion })}`
}
const ckbLightClientVersion = getVerionFromFile(path.join(appPath, '.ckb-light-version'))
if (ckbLightClientVersion) {
applicationVersion += `${t('about.ckb-light-client-version', { version: ckbLightClientVersion })}`
}

const isWin = process.platform === 'win32'

Expand Down
10 changes: 9 additions & 1 deletion packages/neuron-wallet/src/controllers/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,20 @@ export default class WalletsController {

const walletsService = WalletsService.getInstance()
const rpc = generateRPC(NodeService.getInstance().nodeUrl)
let startBlockNumberInLight: string | undefined = undefined
if (!isImporting) {
try {
startBlockNumberInLight = await rpc.getTipBlockNumber()
} catch (error) {
startBlockNumberInLight = undefined
}
}
const wallet = walletsService.create({
id: '',
name,
extendedKey: accountExtendedPublicKey.serialize(),
keystore,
startBlockNumberInLight: isImporting ? undefined : await rpc.getTipBlockNumber()
startBlockNumberInLight,
})

wallet.checkAndGenerateAddresses(isImporting)
Expand Down
6 changes: 6 additions & 0 deletions packages/neuron-wallet/src/exceptions/anyone-can-pay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export class SudtAcpHaveDataError extends Error {
}
}

export class LightClientNotSupportSendToACPError extends Error {
constructor() {
super(t('messages.light-client-sudt-acp-error'))
}
}

export default {
TargetOutputNotFoundError,
AcpSendSameAccountError
Expand Down
6 changes: 4 additions & 2 deletions packages/neuron-wallet/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ export default {
'sudt-acp-have-data': 'The destroying sUDT acp account have amount',
'no-match-address-for-sign': 'Not found matched address',
'target-lock-error': 'CKB asset account can only transfer to sepe256k1 or acp address',
'no-exist-ckb-node-data': '{{path}} has no CKB Node config and storage, press ok to synchronize from scratch'
'no-exist-ckb-node-data': '{{path}} has no CKB Node config and storage, press ok to synchronize from scratch',
'light-client-sudt-acp-error': "Light client mode doesn't support sending assets to other's asset account"
},
messageBox: {
button: {
Expand Down Expand Up @@ -246,7 +247,8 @@ export default {
},
about: {
'app-version': '{{name}} Version: {{version}}',
'ckb-client-version': 'CKB Client Version: {{version}}'
'ckb-client-version': 'CKB Client Version: {{version}}',
'ckb-light-client-version': 'CKB Light Client Version: {{version}}'
},
settings: {
title: {
Expand Down
6 changes: 4 additions & 2 deletions packages/neuron-wallet/src/locales/zh-tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ export default {
'sudt-acp-have-data': '待銷毀的 sUDT 賬戶資產不為 0',
'no-match-address-for-sign': '没有找到匹配的地址',
'target-lock-error': 'CKB 資產只能轉賬到 secp256k1 或者 acp 地址',
'no-exist-ckb-node-data': '{{path}} 目錄下沒有找到 CKB Node 配置和數據, 點擊繼續重新同步'
'no-exist-ckb-node-data': '{{path}} 目錄下沒有找到 CKB Node 配置和數據, 點擊繼續重新同步',
'light-client-sudt-acp-error': '輕節點模式不支持發送資產給其他用戶的資產賬戶'
},
messageBox: {
button: {
Expand Down Expand Up @@ -234,7 +235,8 @@ export default {
},
about: {
'app-version': '{{name}} 版本: {{version}}',
'ckb-client-version': 'CKB 節點版本: {{version}}'
'ckb-client-version': 'CKB 節點版本: {{version}}',
'ckb-light-client-version': 'CKB 輕節點版本: {{version}}'
},
settings: {
title: {
Expand Down
6 changes: 4 additions & 2 deletions packages/neuron-wallet/src/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ export default {
'sudt-acp-have-data': '待销毁的 sUDT 账户资产不为 0',
'no-match-address-for-sign': '没有找到匹配的地址',
'target-lock-error': 'CKB 资产只能转账到 secp256k1 或者 acp 地址',
'no-exist-ckb-node-data': '{{path}} 目录下没有找到 CKB Node 配置和数据, 点击继续重新同步'
'no-exist-ckb-node-data': '{{path}} 目录下没有找到 CKB Node 配置和数据, 点击继续重新同步',
'light-client-sudt-acp-error': '轻节点模式不支持发送资产给其他用户的资产账户'
},
messageBox: {
button: {
Expand Down Expand Up @@ -235,7 +236,8 @@ export default {
},
about: {
'app-version': '{{name}} 版本: {{version}}',
'ckb-client-version': 'CKB 节点版本: {{version}}'
'ckb-client-version': 'CKB 节点版本: {{version}}',
'ckb-light-client-version': 'CKB 轻节点版本: {{version}}'
},
settings: {
title: {
Expand Down
7 changes: 6 additions & 1 deletion packages/neuron-wallet/src/services/anyone-can-pay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Output from 'models/chain/output'
import LiveCell from 'models/chain/live-cell'
import Transaction from 'models/chain/transaction'
import AssetAccountEntity from 'database/chain/entities/asset-account'
import { TargetLockError, TargetOutputNotFoundError } from 'exceptions'
import { LightClientNotSupportSendToACPError, TargetLockError, TargetOutputNotFoundError } from 'exceptions'
import { AcpSendSameAccountError } from 'exceptions'
import Script from 'models/chain/script'
import OutPoint from 'models/chain/out-point'
Expand All @@ -15,6 +15,8 @@ import WalletService from './wallets'
import SystemScriptInfo from 'models/system-script-info'
import CellsService from './cells'
import { MIN_SUDT_CAPACITY } from 'utils/const'
import NetworksService from './networks'
import { NetworkType } from 'models/network'

export default class AnyoneCanPayService {
public static async generateAnyoneCanPayTx(
Expand Down Expand Up @@ -90,6 +92,9 @@ export default class AnyoneCanPayService {
)
if (new AssetAccountInfo().isAnyoneCanPayScript(lockScript)) {
if (!targetOutputLiveCell) {
if (NetworksService.getInstance().getCurrent().type === NetworkType.Light) {
throw new LightClientNotSupportSendToACPError()
}
throw new TargetOutputNotFoundError()
}
return Output.fromObject({
Expand Down
10 changes: 7 additions & 3 deletions packages/neuron-wallet/tests/services/node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ describe('NodeService', () => {
return function() {
return {
getChain: getChainMock,
getLocalNodeInfo: getLocalNodeInfoMock
localNodeInfo: getLocalNodeInfoMock
}
}
})
Expand Down Expand Up @@ -231,7 +231,7 @@ describe('NodeService', () => {
describe('when node starts', () => {
beforeEach(async () => {
stubbedStartCKBNode.mockResolvedValue(true)
await nodeService.tryStartNodeOnDefaultURI()
await nodeService.startNode()

jest.advanceTimersByTime(1000)
});
Expand Down Expand Up @@ -279,7 +279,7 @@ describe('NodeService', () => {
describe('when node failed to start', () => {
beforeEach(async () => {
stubbedStartCKBNode.mockRejectedValue(new Error())
await nodeService.tryStartNodeOnDefaultURI()
await nodeService.startNode()
});
it('logs error', () => {
expect(stubbedLoggerInfo).toHaveBeenCalledWith('CKB: fail to start bundled CKB with error:')
Expand All @@ -295,6 +295,9 @@ describe('NodeService', () => {
})
});
describe('start light node', () => {
beforeEach(() => {
stubbedNetworsServiceGet.mockReset()
})
it('start light node', async () => {
stubbedNetworsServiceGet.mockReturnValueOnce({type: NetworkType.Light})
await nodeService.startNode()
Expand Down Expand Up @@ -333,6 +336,7 @@ describe('NodeService', () => {
})
stubbedStartCKBNode.mockResolvedValue(true)
stubbedNetworsServiceGet.mockReturnValue({remote: bundledNodeUrl})
getLocalNodeInfoMock.mockRejectedValue('not start')
await nodeService.tryStartNodeOnDefaultURI()

await eventCallback({currentNetworkID: 'network1'})
Expand Down