@@ -124,39 +168,13 @@ const MainContent = () => {
- {sameUrlNetworks.length ? (
-
- {t('main.external-node-detected-dialog.body-tips-with-network')}
-
- ) : (
- t('main.external-node-detected-dialog.body-tips-without-network')
- )}
- {sameUrlNetworks.length ? (
- <>
-
- ({
- value: v.id,
- label: `${v.name} (${v.remote})`,
- }))}
- inputIdPrefix="main-switch"
- />
-
-
-
-
- {t('main.external-node-detected-dialog.add-network')}
-
-
- >
- ) : null}
+ {dialogProps.children}
{showEditorDialog ? (
Please allocate more disk space or migrate the data to another disk.",
diff --git a/packages/neuron-ui/src/locales/es.json b/packages/neuron-ui/src/locales/es.json
index 1b5f2a212d..a032e20bec 100644
--- a/packages/neuron-ui/src/locales/es.json
+++ b/packages/neuron-ui/src/locales/es.json
@@ -21,6 +21,7 @@
"special-assets": "Activos personalizados",
"sync-not-start": "Sincronización no iniciada aún",
"connecting": "Conectando",
+ "pause": "Pausar sincronización",
"experimental-functions": "Experimental",
"s-udt": "Cuentas de activos",
"update-neuron-with-ckb": "La versión del nodo de CKB no coincide con Neuron (v{{ version }}), lo que puede causar problemas de compatibilidad. Por favor actualice a la última versión de Neuron.",
@@ -135,7 +136,7 @@
"activity": "Actividad",
"datetime": "Fecha y Hora",
"status": "Estado",
- "amount": "Cantidad",
+ "asset": "Activos",
"address": "Dirección",
"sent": "Enviado",
"sending": "Enviando",
@@ -305,7 +306,7 @@
"name": "Nombre de la Billetera",
"type": "Tipo",
"balance": "Saldo",
- "amount": "Cantidad",
+ "asset": "activos",
"timestamp": "Tiempo",
"status": "Estado",
"operation": "Operación"
@@ -1192,7 +1193,8 @@
"body-tips-without-network": "\"Internal Node\" está reservado para el nodo CKB incorporado, agregue una nueva opción de red para el nodo externo.",
"body-tips-with-network": "\"Internal Node\" está reservado para el nodo CKB incorporado, seleccione una de las siguientes opciones de red o agregue una nueva para el nodo externo.",
"add-network": "Agregar red",
- "ignore-external-node": "Ignorar nodo externo"
+ "ignore-external-node": "Ignorar nodo externo",
+ "external-node-is-light": "Debido a las diferentes suposiciones de seguridad del cliente ligero, Neuron no admite nodos de cliente ligero externos. ¿Desea conectarse a un \"Light Client\" ?"
},
"no-disk-space-dialog": {
"tip": "La sincronización se ha detenido debido a falta de espacio en disco.
Asigne más espacio en disco o migre los datos a otro disco.",
diff --git a/packages/neuron-ui/src/locales/fr.json b/packages/neuron-ui/src/locales/fr.json
index 48bf1295f1..e38beafccc 100644
--- a/packages/neuron-ui/src/locales/fr.json
+++ b/packages/neuron-ui/src/locales/fr.json
@@ -21,6 +21,7 @@
"special-assets": "Actifs personnalisés",
"sync-not-start": "Synchronisation pas encore démarrée",
"connecting": "Connexion",
+ "pause": "Pause synchronisation",
"experimental-functions": "Expérimental",
"s-udt": "Comptes d'actifs",
"update-neuron-with-ckb": "La version du noeud CKB ne correspond pas à Neuron (v{{ version }}), ce qui peut entraîner des problèmes de compatibilité. Veuillez mettre à jour vers la dernière version de Neuron.",
@@ -142,7 +143,7 @@
"activity": "Activité",
"datetime": "Date et heure",
"status": "Statut",
- "amount": "Montant",
+ "asset": "actifs",
"address": "Adresse",
"sent": "Envoyé",
"sending": "Envoi",
@@ -312,7 +313,7 @@
"name": "Nom du Wallet",
"type": "Type",
"balance": "Solde",
- "amount": "Montant",
+ "asset": "actifs",
"timestamp": "Heure",
"status": "Statut",
"operation": "Opération"
@@ -1202,7 +1203,8 @@
"body-tips-without-network": "\"Noeud interne\" est réservé au noeud CKB intégré, veuillez ajouter une nouvelle option réseau pour le noeud externe.",
"body-tips-with-network": "\"Noeud interne\" est réservé au noeud CKB intégré, veuillez sélectionner parmi les options réseau suivantes ou en ajouter une nouvelle pour le noeud externe.",
"add-network": "Ajouter un réseau",
- "ignore-external-node": "Ignorer le noeud externe"
+ "ignore-external-node": "Ignorer le noeud externe",
+ "external-node-is-light": "En raison de différentes hypothèses de sécurité du client léger, Neuron ne prend pas en charge les nœuds clients légers externes. Voulez-vous vous connecter à un \"Light Client\" ?"
},
"no-disk-space-dialog": {
"tip": "En raison d'un espace disque insuffisant, la synchronisation a été interrompue.
Veuillez allouer plus d'espace disque ou migrer les données vers un autre disque.",
diff --git a/packages/neuron-ui/src/locales/zh-tw.json b/packages/neuron-ui/src/locales/zh-tw.json
index 70c7010253..712e024b59 100644
--- a/packages/neuron-ui/src/locales/zh-tw.json
+++ b/packages/neuron-ui/src/locales/zh-tw.json
@@ -21,6 +21,7 @@
"special-assets": "自定義資產",
"sync-not-start": "同步尚未開始",
"connecting": "正在連接節點",
+ "pause": "同步暫停",
"experimental-functions": "實驗性功能",
"s-udt": "資產賬戶",
"update-neuron-with-ckb": "CKB 節點版本與 Neuron (v{{ version }}) 不匹配,可能導致兼容性問題。請更新到最新版 Neuron。",
@@ -136,7 +137,7 @@
"activity": "收支活動",
"datetime": "時間",
"status": "狀態",
- "amount": "金額",
+ "asset": "資產",
"address": "地址",
"sent": "已發送",
"sending": "正在發送",
@@ -308,7 +309,7 @@
"name": "錢包名稱",
"type": "類型",
"balance": "余額",
- "amount": "金額",
+ "asset": "資產",
"timestamp": "時間",
"status": "狀態",
"operation": "操作"
@@ -1205,7 +1206,8 @@
"body-tips-without-network": "\"Internal Node\" 僅用於連接內置節點,請添加新的網絡選項以連接外部節點。",
"body-tips-with-network": "\"Internal Node\" 僅用於連接內置節點,請選擇以下網絡選項或添加新的網絡選項以連接外部節點。",
"add-network": "添加網絡",
- "ignore-external-node": "忽略外部節點"
+ "ignore-external-node": "忽略外部節點",
+ "external-node-is-light": "由於輕客戶端的安全假設不同,Neuron 不支持外部輕客戶端節點。您想連接到 \"Light Client\" 嗎?"
},
"no-disk-space-dialog": {
"tip": "由於磁盤空間不足,同步已停止。
請分配更多磁盤空間或將數據遷移到其他磁盤。",
diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json
index 47efdf422e..b181a569f6 100644
--- a/packages/neuron-ui/src/locales/zh.json
+++ b/packages/neuron-ui/src/locales/zh.json
@@ -21,6 +21,7 @@
"special-assets": "自定义资产",
"sync-not-start": "同步尚未开始",
"connecting": "正在连接节点",
+ "pause": "同步暂停",
"experimental-functions": "实验性功能",
"s-udt": "资产账户",
"update-neuron-with-ckb": "CKB 节点版本与 Neuron (v{{ version }}) 不匹配,可能导致兼容性问题。请更新到最新版 Neuron。",
@@ -135,7 +136,7 @@
"activity": "收支活动",
"datetime": "时间",
"status": "状态",
- "amount": "金额",
+ "asset": "资产",
"address": "地址",
"sent": "已发送",
"sending": "正在发送",
@@ -306,7 +307,7 @@
"name": "钱包名称",
"type": "类型",
"balance": "余额",
- "amount": "金额",
+ "asset": "资产",
"timestamp": "时间",
"status": "状态",
"operation": "操作"
@@ -1204,7 +1205,8 @@
"body-tips-without-network": "\"Internal Node\" 仅用于连接内置节点,请添加新的网络选项以连接外部节点。",
"body-tips-with-network": "\"Internal Node\" 仅用于连接内置节点,请选择以下网络选项或添加新的网络选项以连接外部节点。",
"add-network": "添加网络",
- "ignore-external-node": "忽略外部节点"
+ "ignore-external-node": "忽略外部节点",
+ "external-node-is-light": "由于轻客户端的安全假设不同,Neuron 不支持外部轻客户端节点。您想连接到 \"Light Client\" 吗?"
},
"no-disk-space-dialog": {
"tip": "由于磁盘空间不足,同步已停止。
请分配更多磁盘空间或将数据迁移到其他磁盘。",
diff --git a/packages/neuron-ui/src/services/remote/hardware.ts b/packages/neuron-ui/src/services/remote/hardware.ts
index c0c1cf19d8..9a7f933ccc 100644
--- a/packages/neuron-ui/src/services/remote/hardware.ts
+++ b/packages/neuron-ui/src/services/remote/hardware.ts
@@ -32,7 +32,6 @@ export type Version = string
export const getDevices = remoteApi
('detect-device')
export const getDeviceCkbAppVersion = remoteApi('get-device-ckb-app-version')
-export const getDeviceFirmwareVersion = remoteApi('get-device-firmware-version')
export const getDeviceExtendedPublickey = remoteApi('get-device-extended-public-key')
export const getDevicePublicKey = remoteApi('get-device-public-key')
export const connectDevice = remoteApi('connect-device')
diff --git a/packages/neuron-ui/src/services/remote/multisig.ts b/packages/neuron-ui/src/services/remote/multisig.ts
index 5b5ce1579a..d9c4b48629 100644
--- a/packages/neuron-ui/src/services/remote/multisig.ts
+++ b/packages/neuron-ui/src/services/remote/multisig.ts
@@ -21,6 +21,7 @@ export type MultisigEntity = MultisigParams & {
id?: number
walletId: string
alias?: string
+ startBlockNumber?: number
}
export type MultisigConfig = MultisigEntity & {
@@ -52,3 +53,4 @@ export const loadMultisigTxJson = remoteApi('load-multi
export const getMultisigSyncProgress = remoteApi(
'get-sync-progress-by-addresses'
)
+export const changeMultisigSyncStatus = remoteApi('change-multisig-sync-status')
diff --git a/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts b/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts
index 8640a2c384..c8cb6f0722 100644
--- a/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts
+++ b/packages/neuron-ui/src/services/remote/remoteApiWrapper.ts
@@ -132,7 +132,6 @@ type Action =
// Hardware Wallet
| 'detect-device'
| 'get-device-ckb-app-version'
- | 'get-device-firmware-version'
| 'get-device-public-key'
| 'get-device-extended-public-key'
| 'connect-device'
@@ -160,6 +159,7 @@ type Action =
| 'get-hold-sudt-cell-capacity'
| 'start-migrate'
| 'get-sync-progress-by-addresses'
+ | 'change-multisig-sync-status'
// spore
| 'generate-transfer-spore-tx'
// cell-manage
diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts
index 2d64d0c029..801a9fe30c 100644
--- a/packages/neuron-ui/src/states/stateProvider/reducer.ts
+++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts
@@ -328,7 +328,7 @@ export const reducer = produce((state: Draft, action:
}
case AppActions.DismissNotification: {
/**
- * payload: timstamp
+ * payload: timestamp
*/
state.app.showTopAlert =
state.app.notifications.findIndex(message => message.timestamp === action.payload) ===
diff --git a/packages/neuron-ui/src/types/App/index.d.ts b/packages/neuron-ui/src/types/App/index.d.ts
index 76ce82827b..2a237caef5 100644
--- a/packages/neuron-ui/src/types/App/index.d.ts
+++ b/packages/neuron-ui/src/types/App/index.d.ts
@@ -19,6 +19,7 @@ declare namespace State {
data: string
}
assetAccountType?: 'CKB' | 'sUDT' | string
+ daoCapacity?: string
}
interface DetailedInput {
@@ -238,7 +239,7 @@ declare namespace State {
balance: string
addresses: Address[]
}
- type ConnectionStatus = 'online' | 'offline' | 'connecting'
+ type ConnectionStatus = 'online' | 'offline' | 'connecting' | 'pause'
type SyncState = Readonly<{
cacheTipBlockNumber: number
diff --git a/packages/neuron-ui/src/utils/enums.ts b/packages/neuron-ui/src/utils/enums.ts
index 647f421446..747c8398a5 100644
--- a/packages/neuron-ui/src/utils/enums.ts
+++ b/packages/neuron-ui/src/utils/enums.ts
@@ -2,6 +2,8 @@ export enum ConnectionStatus {
Online = 'online',
Offline = 'offline',
Connecting = 'connecting',
+ // pasue by open multisig address with light client
+ Pause = 'pause',
}
export enum RoutePath {
diff --git a/packages/neuron-ui/src/widgets/Button/index.tsx b/packages/neuron-ui/src/widgets/Button/index.tsx
index 9de7ef9f19..9d4e6e276e 100644
--- a/packages/neuron-ui/src/widgets/Button/index.tsx
+++ b/packages/neuron-ui/src/widgets/Button/index.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { ButtonHTMLAttributes } from 'react'
import Spinner from 'widgets/Spinner'
import styles from './button.module.scss'
@@ -20,13 +20,9 @@ const Button = React.forwardRef(
}: {
type?: 'default' | 'cancel' | 'ok' | 'submit' | 'confirm' | 'primary' | 'reset' | 'text'
label?: string
- onClick?: any
- disabled?: boolean
className?: string
- children?: React.ReactChild
loading?: boolean
- [key: string]: any
- },
+ } & Omit, 'type'>,
ref: React.LegacyRef
) => {
const btnType = isNativeType(type) ? type : 'button'
diff --git a/packages/neuron-ui/src/widgets/Icons/NoDiskSpaceWarn.png b/packages/neuron-ui/src/widgets/Icons/Attention.png
similarity index 100%
rename from packages/neuron-ui/src/widgets/Icons/NoDiskSpaceWarn.png
rename to packages/neuron-ui/src/widgets/Icons/Attention.png
diff --git a/packages/neuron-ui/src/widgets/Icons/icon.tsx b/packages/neuron-ui/src/widgets/Icons/icon.tsx
index 131b0387c6..21eabcb23a 100644
--- a/packages/neuron-ui/src/widgets/Icons/icon.tsx
+++ b/packages/neuron-ui/src/widgets/Icons/icon.tsx
@@ -59,6 +59,9 @@ import { ReactComponent as ImportKeystoreSvg } from './SoftWalletImportKeystore.
import { ReactComponent as ImportHardwareSvg } from './HardWalletImport.svg'
import { ReactComponent as DepositTimeSortSvg } from './DepositTimeSort.svg'
import { ReactComponent as QuestionSvg } from './Question.svg'
+import { ReactComponent as DetailsSvg } from './Details.svg'
+import { ReactComponent as ConfirmSvg } from './Confirm.svg'
+import { ReactComponent as UploadSvg } from './Upload.svg'
import styles from './icon.module.scss'
@@ -134,3 +137,6 @@ export const ImportKeystore = WrapSvg(ImportKeystoreSvg)
export const ImportHardware = WrapSvg(ImportHardwareSvg)
export const DepositTimeSort = WrapSvg(DepositTimeSortSvg)
export const Question = WrapSvg(QuestionSvg)
+export const Details = WrapSvg(DetailsSvg)
+export const Confirm = WrapSvg(ConfirmSvg)
+export const Upload = WrapSvg(UploadSvg)
diff --git a/packages/neuron-ui/src/widgets/MigrateCkbDataDialog/index.tsx b/packages/neuron-ui/src/widgets/MigrateCkbDataDialog/index.tsx
index d323c05c7e..536c1b17ff 100644
--- a/packages/neuron-ui/src/widgets/MigrateCkbDataDialog/index.tsx
+++ b/packages/neuron-ui/src/widgets/MigrateCkbDataDialog/index.tsx
@@ -47,7 +47,7 @@ const MigrateCkbDataDialog = ({
[currentPath, onConfirm]
)
const onActionClick = useCallback(
- (e: React.MouseEvent) => {
+ (e: React.MouseEvent) => {
if (e.currentTarget.dataset.syncType) {
startSync(e.currentTarget.dataset.syncType)
}
diff --git a/packages/neuron-wallet/.env b/packages/neuron-wallet/.env
index f32862920f..3c4d9296b8 100644
--- a/packages/neuron-wallet/.env
+++ b/packages/neuron-wallet/.env
@@ -117,5 +117,5 @@ DAO_CODE_HASH=0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e
MULTISIG_CODE_HASH=0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8
# CKB NODE OPTIONS
-CKB_NODE_ASSUME_VALID_TARGET='0x9443ad8da9172d484367bc5467988cba7a0c46028398309edfdda7d2d79be897'
-CKB_NODE_DATA_SIZE=53
+CKB_NODE_ASSUME_VALID_TARGET='0x6dd077b407d019a0bce0cbad8c34e69a524ae4b2599b9feda2c7491f3559d32c'
+CKB_NODE_DATA_SIZE=54
diff --git a/packages/neuron-wallet/package.json b/packages/neuron-wallet/package.json
index 77479adeae..a5fd0c7891 100644
--- a/packages/neuron-wallet/package.json
+++ b/packages/neuron-wallet/package.json
@@ -3,7 +3,7 @@
"productName": "Neuron",
"description": "CKB Neuron Wallet",
"homepage": "https://www.nervos.org/",
- "version": "0.114.3",
+ "version": "0.116.2",
"private": true,
"author": {
"name": "Nervos Core Dev",
@@ -97,7 +97,7 @@
"electron-builder": "24.9.1",
"electron-devtools-installer": "3.2.0",
"jest-when": "3.6.0",
- "neuron-ui": "0.114.3",
+ "neuron-ui": "0.116.2",
"typescript": "5.3.3"
}
}
diff --git a/packages/neuron-wallet/src/block-sync-renderer/index.ts b/packages/neuron-wallet/src/block-sync-renderer/index.ts
index cf690f014b..892c676618 100644
--- a/packages/neuron-wallet/src/block-sync-renderer/index.ts
+++ b/packages/neuron-wallet/src/block-sync-renderer/index.ts
@@ -9,22 +9,20 @@ import DataUpdateSubject from '../models/subjects/data-update'
import AddressCreatedSubject from '../models/subjects/address-created-subject'
import WalletDeletedSubject from '../models/subjects/wallet-deleted-subject'
import TxDbChangedSubject from '../models/subjects/tx-db-changed-subject'
-import { LumosCellQuery, LumosCell } from './sync/synchronizer'
+import { type Cell, type QueryOptions } from '@ckb-lumos/base'
import { WorkerMessage, StartParams, QueryIndexerParams } from './task'
import logger from '../utils/logger'
import CommonUtils from '../utils/common'
import queueWrapper from '../utils/queue'
import env from '../env'
import MultisigConfigDbChangedSubject from '../models/subjects/multisig-config-db-changed-subject'
-import Multisig from '../services/multisig'
-import { SyncAddressType } from '../database/chain/entities/sync-progress'
-import { debounceTime } from 'rxjs/operators'
import { TransactionPersistor } from '../services/tx'
let network: Network | null
let child: ChildProcess | null = null
let requestId = 0
let requests = new Map unknown>>()
+let isSyncMultisigWithLight = false
export const killBlockSyncTask = async () => {
const _child = child
@@ -88,7 +86,7 @@ export const switchToNetwork = async (newNetwork: Network, reconnected = false,
await resetSyncTaskQueue.asyncPush(shouldSync)
}
-export const queryIndexer = async (query: LumosCellQuery): Promise => {
+export const queryIndexer = async (query: QueryOptions): Promise => {
const _child = child
if (!_child) {
return []
@@ -102,7 +100,7 @@ export const queryIndexer = async (query: LumosCellQuery): Promise
return registerRequest(_child, msg).catch(err => {
logger.error(`Sync:\tfailed to register query indexer task`, err)
return []
- }) as Promise
+ }) as Promise
}
export const createBlockSyncTask = async () => {
@@ -177,8 +175,8 @@ export const createBlockSyncTask = async () => {
genesisHash: network.genesisHash,
url: network.remote,
addressMetas,
- indexerUrl: network.remote,
nodeType: network.type,
+ syncMultisig: isSyncMultisigWithLight,
}
const msg: Required> = { type: 'call', channel: 'start', id: requestId++, message }
return registerRequest(_child, msg).catch(err => {
@@ -200,17 +198,10 @@ export const registerRequest = (c: ChildProcess, msg: Required) =
AddressCreatedSubject.getSubject().subscribe(() => resetSyncTaskQueue.asyncPush(true))
WalletDeletedSubject.getSubject().subscribe(() => resetSyncTaskQueue.asyncPush(true))
-MultisigConfigDbChangedSubject.getSubject()
- .pipe(debounceTime(1000))
- .subscribe(async () => {
- if (!child) {
- return
- }
- const appendScripts = await Multisig.getMultisigConfigForLight()
- const msg: Required<
- WorkerMessage<{ walletId: string; script: CKBComponents.Script; addressType: SyncAddressType }[]>
- > = { type: 'call', channel: 'append_scripts', id: requestId++, message: appendScripts }
- return registerRequest(child, msg).catch(err => {
- logger.error(`Sync:\ffailed to append script to light client`, err)
- })
- })
+MultisigConfigDbChangedSubject.getSubject().subscribe(() => resetSyncTaskQueue.asyncPush(true))
+
+export async function changeMultisigSyncStatus(status: boolean) {
+ logger.info(`Sync:\t ${status ? 'start' : 'stop'} multisig sync`)
+ isSyncMultisigWithLight = status
+ await resetSyncTask(true)
+}
diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/full-synchronizer.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/full-synchronizer.ts
index 972d37e5f0..eecace1ccf 100644
--- a/packages/neuron-wallet/src/block-sync-renderer/sync/full-synchronizer.ts
+++ b/packages/neuron-wallet/src/block-sync-renderer/sync/full-synchronizer.ts
@@ -10,8 +10,8 @@ import IndexerCacheService from './indexer-cache-service'
export default class FullSynchronizer extends Synchronizer {
private rpcService: RpcService
- constructor(addresses: Address[], nodeUrl: string, indexerUrl: string, nodeType: NetworkType) {
- super({ addresses, nodeUrl, indexerUrl })
+ constructor(addresses: Address[], nodeUrl: string, nodeType: NetworkType) {
+ super({ addresses, nodeUrl })
this.rpcService = new RpcService(nodeUrl, nodeType)
}
diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts
index f87dddf99b..fe89dabefb 100644
--- a/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts
+++ b/packages/neuron-wallet/src/block-sync-renderer/sync/light-synchronizer.ts
@@ -4,7 +4,7 @@ import { Address } from '../../models/address'
import AddressMeta from '../../database/address/meta'
import { scheduler } from 'timers/promises'
import SyncProgressService from '../../services/sync-progress'
-import { Synchronizer, AppendScript } from './synchronizer'
+import { Synchronizer } from './synchronizer'
import { computeScriptHash as scriptToHash } from '@ckb-lumos/base/lib/utils'
import { FetchTransactionReturnType, LightRPC, LightScriptFilter } from '../../utils/ckb-rpc'
import Multisig from '../../services/multisig'
@@ -23,17 +23,15 @@ import NetworksService from '../../services/networks'
import { getConnection } from '../../database/chain/connection'
const unpackGroup = molecule.vector(blockchain.OutPoint)
+const THRESHOLD_BLOCK_NUMBER_IN_DIFF_WALLET = 100_000
export default class LightSynchronizer extends Synchronizer {
private lightRpc: LightRPC
private addressMetas: AddressMeta[]
+ private syncMultisig?: boolean
constructor(addresses: Address[], nodeUrl: string) {
- super({
- addresses,
- nodeUrl,
- indexerUrl: nodeUrl,
- })
+ super({ addresses, nodeUrl })
this.lightRpc = new LightRPC(nodeUrl)
this.addressMetas = addresses.map(address => AddressMeta.fromObject(address))
// fetch some dep cell
@@ -87,7 +85,9 @@ export default class LightSynchronizer extends Synchronizer {
private async synchronize() {
const syncScripts = await this.upsertTxHashes()
await this.updateSyncedBlockOfScripts(syncScripts)
- const minSyncBlockNumber = await SyncProgressService.getCurrentWalletMinSyncedBlockNumber()
+ const minSyncBlockNumber = await SyncProgressService.getCurrentWalletMinSyncedBlockNumber(
+ this.syncMultisig ? SyncAddressType.Multisig : undefined
+ )
const hasNextBlock = await this.notifyAndSyncNext(minSyncBlockNumber)
if (!hasNextBlock) {
await this.updateBlockStartNumber(minSyncBlockNumber)
@@ -171,20 +171,32 @@ export default class LightSynchronizer extends Synchronizer {
await getConnection('light').manager.save(updatedSyncProgress, { chunk: 100 })
}
- private async initSyncProgress(appendScripts: AppendScript[] = []) {
- if (!this.addressMetas.length && !appendScripts.length) {
+ private static async getWalletsSyncedMinBlockNumber() {
+ const walletMinBlockNumber = await SyncProgressService.getWalletMinLocalSavedBlockNumber()
+ const wallets = await WalletService.getInstance().getAll()
+ return wallets.reduce>(
+ (pre, cur) => ({
+ ...pre,
+ [cur.id]: Math.max(parseInt(cur.startBlockNumber ?? '0x0'), walletMinBlockNumber?.[cur.id] ?? 0),
+ }),
+ {}
+ )
+ }
+
+ private async initSyncProgress() {
+ if (!this.addressMetas.length) {
return
}
const existSyncArgses = await SyncProgressService.getExistingSyncArgses()
const syncScripts = await this.lightRpc.getScripts()
const retainedSyncScripts = syncScripts.filter(v => existSyncArgses.has(v.script.args))
- const existSyncscripts: Record = {}
+ const existSyncScripts: Record = {}
retainedSyncScripts.forEach(v => {
- existSyncscripts[scriptToHash(v.script)] = v
+ existSyncScripts[scriptToHash(v.script)] = v
})
+ const walletMinBlockNumber = await LightSynchronizer.getWalletsSyncedMinBlockNumber()
const currentWalletId = WalletService.getInstance().getCurrent()?.id
const allScripts = this.addressMetas
- .filter(v => (currentWalletId ? v.walletId === currentWalletId : true))
.map(addressMeta => {
const lockScripts = [
addressMeta.generateDefaultLockScript(),
@@ -198,56 +210,81 @@ export default class LightSynchronizer extends Synchronizer {
}))
})
.flat()
- const walletMinBlockNumber = await SyncProgressService.getWalletMinLocalSavedBlockNumber()
- const wallets = await WalletService.getInstance().getAll()
- const walletStartBlockMap = wallets.reduce>(
- (pre, cur) => ({ ...pre, [cur.id]: cur.startBlockNumber }),
- {}
- )
- const otherTypeSyncBlockNumber = await SyncProgressService.getOtherTypeSyncBlockNumber()
- const addScripts = [
- ...allScripts
- .filter(
- v =>
- !existSyncscripts[scriptToHash(v.script)] ||
- +existSyncscripts[scriptToHash(v.script)].blockNumber < +(walletStartBlockMap[v.walletId] ?? 0)
+ .filter(v => {
+ return (
+ !currentWalletId ||
+ v.walletId === currentWalletId ||
+ walletMinBlockNumber[v.walletId] >
+ walletMinBlockNumber[currentWalletId] - THRESHOLD_BLOCK_NUMBER_IN_DIFF_WALLET
)
- .map(v => {
- const blockNumber = Math.max(
- parseInt(walletStartBlockMap[v.walletId] ?? '0x0'),
- walletMinBlockNumber?.[v.walletId] ?? 0
- )
- return {
- ...v,
- blockNumber: `0x${blockNumber.toString(16)}`,
- }
- }),
- ...appendScripts
- .filter(v => !existSyncscripts[scriptToHash(v.script)])
- .map(v => ({
+ })
+ const addScripts = allScripts
+ .filter(v => {
+ const scriptHash = scriptToHash(v.script)
+ return (
+ !existSyncScripts[scriptHash] || +existSyncScripts[scriptHash].blockNumber < walletMinBlockNumber[v.walletId]
+ )
+ })
+ .map(v => {
+ return {
...v,
- blockNumber: `0x${(otherTypeSyncBlockNumber[scriptToHash(v.script)] ?? 0).toString(16)}`,
- })),
- ]
+ blockNumber: `0x${walletMinBlockNumber[v.walletId].toString(16)}`,
+ }
+ })
await this.lightRpc.setScripts(addScripts, 'partial')
- const allScriptHashes = new Set([
- ...allScripts.map(v => scriptToHash(v.script)),
- ...appendScripts.map(v => scriptToHash(v.script)),
- ])
+ const allScriptHashes = new Set(allScripts.map(v => scriptToHash(v.script)))
const deleteScript = retainedSyncScripts.filter(v => !allScriptHashes.has(scriptToHash(v.script)))
await this.lightRpc.setScripts(deleteScript, 'delete')
const walletIds = [...new Set(this.addressMetas.map(v => v.walletId))]
await SyncProgressService.initSyncProgress(addScripts)
await SyncProgressService.updateSyncProgressFlag(walletIds)
+ }
+
+ private async initMultisigSyncProgress() {
+ const multisigScripts = await Multisig.getMultisigConfigForLight()
+ if (!multisigScripts.length) {
+ return
+ }
+ const existSyncArgses = await SyncProgressService.getExistingSyncArgses()
+ const syncScripts = await this.lightRpc.getScripts()
+ const retainedSyncScripts = syncScripts.filter(v => existSyncArgses.has(v.script.args))
+ const existSyncScripts: Record = {}
+ retainedSyncScripts.forEach(v => {
+ existSyncScripts[scriptToHash(v.script)] = v
+ })
+ const otherTypeSyncBlockNumber = await SyncProgressService.getOtherTypeSyncBlockNumber()
+ const addScripts = multisigScripts
+ .filter(v => {
+ const scriptHash = scriptToHash(v.script)
+ return (
+ !existSyncScripts[scriptToHash(v.script)] ||
+ +existSyncScripts[scriptHash].blockNumber < (v.startBlockNumber ?? 0)
+ )
+ })
+ .map(v => ({
+ ...v,
+ blockNumber: `0x${Math.max(
+ otherTypeSyncBlockNumber[scriptToHash(v.script)] ?? 0,
+ v.startBlockNumber ?? 0
+ ).toString(16)}`,
+ }))
+ await this.lightRpc.setScripts(addScripts, 'partial')
+ const allScriptHashes = new Set(multisigScripts.map(v => scriptToHash(v.script)))
+ const deleteScript = retainedSyncScripts.filter(v => !allScriptHashes.has(scriptToHash(v.script)))
+ await this.lightRpc.setScripts(deleteScript, 'delete')
+ await SyncProgressService.initSyncProgress(addScripts)
await SyncProgressService.removeByHashesAndAddressType(
SyncAddressType.Multisig,
- appendScripts.map(v => scriptToHash(v.script))
+ multisigScripts.map(v => scriptToHash(v.script))
)
}
- private async initSync() {
- const appendScripts = await Multisig.getMultisigConfigForLight()
- await this.initSyncProgress(appendScripts)
+ private async initSync(syncMultisig?: boolean) {
+ if (syncMultisig) {
+ await this.initMultisigSyncProgress()
+ } else {
+ await this.initSyncProgress()
+ }
while (this.pollingIndexer) {
await this.synchronize()
await scheduler.wait(5000)
@@ -284,21 +321,18 @@ export default class LightSynchronizer extends Synchronizer {
)
}
- public async connect() {
+ public async connect(syncMultisig?: boolean) {
try {
logger.info('LightConnector:\tconnect ...:')
this.pollingIndexer = true
- this.initSync()
+ this.syncMultisig = syncMultisig
+ this.initSync(syncMultisig)
} catch (error) {
logger.error(`Error connecting to Light: ${error.message}`)
throw error
}
}
- async appendScript(scripts: AppendScript[]) {
- this.initSyncProgress(scripts)
- }
-
private async checkTxExist(txHashes: string[]) {
const transactions = await this.lightRpc
.createBatchRequest<'getTransaction', string[], TransactionWithStatus[]>(txHashes.map(v => ['getTransaction', v]))
@@ -308,7 +342,9 @@ export default class LightSynchronizer extends Synchronizer {
async processTxsInNextBlockNumber() {
const [nextBlockNumber, txHashesInNextBlock] = await this.getTxHashesWithNextUnprocessedBlockNumber()
- const minSyncBlockNumber = await SyncProgressService.getCurrentWalletMinSyncedBlockNumber()
+ const minSyncBlockNumber = await SyncProgressService.getCurrentWalletMinSyncedBlockNumber(
+ this.syncMultisig ? SyncAddressType.Multisig : undefined
+ )
if (
nextBlockNumber !== undefined &&
txHashesInNextBlock.length &&
@@ -330,7 +366,9 @@ export default class LightSynchronizer extends Synchronizer {
} else {
return
}
- const minCachedBlockNumber = await SyncProgressService.getCurrentWalletMinSyncedBlockNumber()
+ const minCachedBlockNumber = await SyncProgressService.getCurrentWalletMinSyncedBlockNumber(
+ this.syncMultisig ? SyncAddressType.Multisig : undefined
+ )
await this.updateBlockStartNumber(Math.min(parseInt(blockNumber), minCachedBlockNumber))
this.processNextBlockNumber()
}
diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts
index 027bc14967..8eb2b923f3 100644
--- a/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts
+++ b/packages/neuron-wallet/src/block-sync-renderer/sync/queue.ts
@@ -17,10 +17,9 @@ import IndexerCacheService from './indexer-cache-service'
import logger from '../../utils/logger'
import CommonUtils from '../../utils/common'
import { ShouldInChildProcess } from '../../exceptions'
-import { AppendScript, BlockTips, Synchronizer } from './synchronizer'
+import { BlockTips, Synchronizer } from './synchronizer'
import LightSynchronizer from './light-synchronizer'
import { generateRPC } from '../../utils/ckb-rpc'
-import { BUNDLED_LIGHT_CKB_URL } from '../../utils/const'
import { NetworkType } from '../../models/network'
import WalletService from '../../services/wallets'
@@ -28,7 +27,6 @@ export default class Queue {
#lockHashes: string[]
#url: string // ckb node
#nodeType: NetworkType
- #indexerUrl: string
#addresses: AddressInterface[]
#rpcService: RpcService
#indexerConnector: Synchronizer | undefined
@@ -38,15 +36,16 @@ export default class Queue {
#multiSignBlake160s: string[]
#anyoneCanPayLockHashes: string[]
#assetAccountInfo: AssetAccountInfo
+ #syncMultisig: boolean
- constructor(url: string, addresses: AddressInterface[], indexerUrl: string, nodeType: NetworkType) {
+ constructor(url: string, addresses: AddressInterface[], nodeType: NetworkType, syncMultisig: boolean) {
this.#url = url
- this.#indexerUrl = indexerUrl
this.#addresses = addresses
this.#rpcService = new RpcService(url, nodeType)
this.#nodeType = nodeType
this.#assetAccountInfo = new AssetAccountInfo()
this.#lockHashes = AddressParser.batchToLockHash(this.#addresses.map(meta => meta.address))
+ this.#syncMultisig = syncMultisig
const blake160s = this.#addresses.map(meta => meta.blake160)
this.#lockArgsSet = new Set(
@@ -67,12 +66,12 @@ export default class Queue {
start = async () => {
logger.info('Queue:\tstart')
try {
- if (this.#url === BUNDLED_LIGHT_CKB_URL) {
+ if (this.#nodeType === NetworkType.Light) {
this.#indexerConnector = new LightSynchronizer(this.#addresses, this.#url)
} else {
- this.#indexerConnector = new FullSynchronizer(this.#addresses, this.#url, this.#indexerUrl, this.#nodeType)
+ this.#indexerConnector = new FullSynchronizer(this.#addresses, this.#url, this.#nodeType)
}
- await this.#indexerConnector!.connect()
+ await this.#indexerConnector!.connect(this.#syncMultisig)
} catch (error) {
logger.error('Restarting child process due to error', error.message)
if (process.send) {
@@ -122,10 +121,6 @@ export default class Queue {
}
}
- async appendLightScript(scripts: AppendScript[]) {
- await this.#indexerConnector?.appendScript(scripts)
- }
-
private async fetchTxsWithStatus(txHashes: string[]) {
const rpc = generateRPC(this.#url, this.#nodeType)
const txsWithStatus = await rpc
@@ -272,6 +267,7 @@ export default class Queue {
indexerTipNumber: tip.indexerTipNumber,
cacheTipNumber: tip.cacheTipNumber,
timestamp: Date.now(),
+ syncMultisig: this.#syncMultisig,
},
})
} else {
diff --git a/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts b/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts
index b8d1a789a2..ff9c576f8c 100644
--- a/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts
+++ b/packages/neuron-wallet/src/block-sync-renderer/sync/synchronizer.ts
@@ -1,10 +1,9 @@
import { Subject } from 'rxjs'
import { queue, QueueObject } from 'async'
+import { type QueryOptions } from '@ckb-lumos/base'
import { Indexer as CkbIndexer, CellCollector } from '@ckb-lumos/ckb-indexer'
-import { QueryOptions } from '@ckb-lumos/base'
import AddressMeta from '../../database/address/meta'
import { Address } from '../../models/address'
-import { SyncAddressType } from '../../database/chain/entities/sync-progress'
import IndexerCacheService from './indexer-cache-service'
import logger from '../../utils/logger'
import IndexerTxHashCache from '../../database/chain/entities/indexer-tx-hash-cache'
@@ -14,41 +13,6 @@ export interface BlockTips {
indexerTipNumber: number | undefined
}
-export interface LumosCellQuery {
- lock: CKBComponents.Script | null
- type: CKBComponents.Script | null
- data: string | null
-}
-
-export interface LumosCell {
- blockHash: string
- outPoint: {
- txHash: string
- index: string
- }
- cellOutput: {
- capacity: string
- lock: {
- codeHash: string
- args: string
- hashType: string
- }
- type?: {
- codeHash: string
- args: string
- hashType: string
- }
- }
- data?: string
-}
-
-export interface AppendScript {
- walletId: string
- script: CKBComponents.Script
- addressType: SyncAddressType
- scriptType: CKBRPC.ScriptType
-}
-
export abstract class Synchronizer {
public readonly blockTipsSubject: Subject = new Subject()
public readonly transactionsSubject = new Subject<{ txHashes: CKBComponents.Hash[]; params: string }>()
@@ -57,19 +21,16 @@ export abstract class Synchronizer {
protected processingBlockNumber?: string
protected addressesByWalletId: Map = new Map()
protected pollingIndexer: boolean = false
- private indexerQueryQueue: QueueObject | undefined
+ private indexerQueryQueue: QueueObject | undefined
protected _needGenerateAddress: boolean = false
- abstract connect(): Promise
+ abstract connect(syncMultisig?: boolean): Promise
abstract processTxsInNextBlockNumber(): Promise
protected abstract upsertTxHashes(): Promise
public abstract notifyCurrentBlockNumberProcessed(blockNumber: string): Promise
- async appendScript(_scripts: AppendScript[]) {
- // do nothing
- }
- constructor({ addresses, nodeUrl, indexerUrl }: { addresses: Address[]; nodeUrl: string; indexerUrl: string }) {
- this.indexer = new CkbIndexer(nodeUrl, indexerUrl)
+ constructor({ addresses, nodeUrl }: { addresses: Address[]; nodeUrl: string }) {
+ this.indexer = new CkbIndexer(nodeUrl)
this.addressesByWalletId = addresses
.map(address => AddressMeta.fromObject(address))
.reduce((addressesByWalletId, addressMeta) => {
@@ -155,7 +116,7 @@ export abstract class Synchronizer {
return false
}
- public async getLiveCellsByScript(query: LumosCellQuery) {
+ public async getLiveCellsByScript(query: QueryOptions) {
return new Promise((resolve, reject) => {
this.indexerQueryQueue!.push(query, (err: any, result: unknown) => {
if (err) {
@@ -166,7 +127,7 @@ export abstract class Synchronizer {
})
}
- private async collectLiveCellsByScript(query: LumosCellQuery) {
+ private async collectLiveCellsByScript(query: QueryOptions) {
const { lock, type, data } = query
if (!lock && !type) {
throw new Error('at least one parameter is required')
diff --git a/packages/neuron-wallet/src/block-sync-renderer/task.ts b/packages/neuron-wallet/src/block-sync-renderer/task.ts
index e10291360e..124a781fdd 100644
--- a/packages/neuron-wallet/src/block-sync-renderer/task.ts
+++ b/packages/neuron-wallet/src/block-sync-renderer/task.ts
@@ -1,4 +1,4 @@
-import type { LumosCellQuery } from './sync/synchronizer'
+import { type QueryOptions } from '@ckb-lumos/base'
import initConnection from '../database/chain/ormconfig'
import { register as registerTxStatusListener } from './tx-status-listener'
import SyncQueue from './sync/queue'
@@ -21,7 +21,6 @@ export interface WorkerMessage {
| 'address-created'
| 'indexer-error'
| 'check-and-save-wallet-address'
- | 'append_scripts'
message: T
}
@@ -31,11 +30,11 @@ export interface StartParams {
genesisHash: string
url: SyncQueueParams[0]
addressMetas: SyncQueueParams[1]
- indexerUrl: SyncQueueParams[2]
- nodeType: SyncQueueParams[3]
+ nodeType: SyncQueueParams[2]
+ syncMultisig: SyncQueueParams[3]
}
-export type QueryIndexerParams = LumosCellQuery
+export type QueryIndexerParams = QueryOptions
export const listener = async ({ type, id, channel, message }: WorkerMessage) => {
if (type === 'kill') {
@@ -63,7 +62,7 @@ export const listener = async ({ type, id, channel, message }: WorkerMessage) =>
try {
await initConnection(message.genesisHash)
- syncQueue = new SyncQueue(message.url, message.addressMetas, message.indexerUrl, message.nodeType)
+ syncQueue = new SyncQueue(message.url, message.addressMetas, message.nodeType, message.syncMultisig)
syncQueue.start()
} catch (err) {
logger.error(`Block Sync Task:\t`, err)
@@ -93,12 +92,6 @@ export const listener = async ({ type, id, channel, message }: WorkerMessage) =>
}
break
}
- case 'append_scripts': {
- if (Array.isArray(message)) {
- await syncQueue?.appendLightScript(message)
- }
- break
- }
default: {
// ignore
}
diff --git a/packages/neuron-wallet/src/controllers/api.ts b/packages/neuron-wallet/src/controllers/api.ts
index fa209b0887..911baa4d96 100644
--- a/packages/neuron-wallet/src/controllers/api.ts
+++ b/packages/neuron-wallet/src/controllers/api.ts
@@ -59,7 +59,7 @@ import startMonitor, { stopMonitor } from '../services/monitor'
import { migrateCkbData } from '../services/ckb-runner'
import NodeService from '../services/node'
import SyncProgressService from '../services/sync-progress'
-import { resetSyncTaskQueue } from '../block-sync-renderer'
+import { changeMultisigSyncStatus, resetSyncTaskQueue } from '../block-sync-renderer'
import DataUpdateSubject from '../models/subjects/data-update'
import CellManagement from './cell-management'
import { UpdateCellLocalInfo } from '../database/chain/entities/cell-local-info'
@@ -836,10 +836,6 @@ export default class ApiController {
return this.#hardwareController.getCkbAppVersion()
})
- handle('get-device-firmware-version', async () => {
- return this.#hardwareController.getFirmwareVersion()
- })
-
handle('get-device-extended-public-key', async () => {
return this.#hardwareController.getExtendedPublicKey()
})
@@ -917,6 +913,13 @@ export default class ApiController {
return this.#multisigController.loadMultisigTxJson(fullPayload)
})
+ handle('change-multisig-sync-status', (_, status: boolean) => {
+ changeMultisigSyncStatus(status)
+ return {
+ status: ResponseCode.Success,
+ }
+ })
+
//migrate
handle('start-migrate', async () => {
migrateCkbData()
diff --git a/packages/neuron-wallet/src/controllers/hardware.ts b/packages/neuron-wallet/src/controllers/hardware.ts
index 182381ba61..e8e9aa0cfa 100644
--- a/packages/neuron-wallet/src/controllers/hardware.ts
+++ b/packages/neuron-wallet/src/controllers/hardware.ts
@@ -38,16 +38,6 @@ export default class HardwareController {
}
}
- public async getFirmwareVersion(): Promise> {
- const device = HardwareWalletService.getInstance().getCurrent()!
- const version = await device.getFirmwareVersion?.()
-
- return {
- status: ResponseCode.Success,
- result: version,
- }
- }
-
public async getExtendedPublicKey(): Promise> {
const device = HardwareWalletService.getInstance().getCurrent()!
const pubkey = await device.getExtendedPublicKey()
diff --git a/packages/neuron-wallet/src/controllers/multisig.ts b/packages/neuron-wallet/src/controllers/multisig.ts
index ea41a69bb1..9ba5bc5ac3 100644
--- a/packages/neuron-wallet/src/controllers/multisig.ts
+++ b/packages/neuron-wallet/src/controllers/multisig.ts
@@ -14,6 +14,10 @@ import Multisig from '../models/multisig'
import SystemScriptInfo from '../models/system-script-info'
import NetworksService from '../services/networks'
import ShowGlobalDialogSubject from '../models/subjects/show-global-dialog'
+import { NetworkType } from '../models/network'
+import MultisigConfigDbChangedSubject from '../models/subjects/multisig-config-db-changed-subject'
+import { LightRPC } from '../utils/ckb-rpc'
+import SyncProgressService from '../services/sync-progress'
interface MultisigConfigOutput {
multisig_configs: Record<
@@ -55,6 +59,23 @@ export default class MultisigController {
}
}
+ async resetMultisigSync(config: MultisigConfig, startBlockNumber: number) {
+ const network = NetworksService.getInstance().getCurrent()
+ const lightRpc = new LightRPC(network.remote)
+ const script = Multisig.getMultisigScript(config.blake160s, config.r, config.m, config.n)
+ await lightRpc.setScripts(
+ [
+ {
+ script,
+ blockNumber: `0x${startBlockNumber.toString(16)}`,
+ scriptType: 'lock' as CKBRPC.ScriptType,
+ },
+ ],
+ 'partial'
+ )
+ SyncProgressService.resetMultisigSync(scriptToHash(script), startBlockNumber)
+ }
+
async updateConfig(params: {
id: number
walletId?: string
@@ -63,8 +84,19 @@ export default class MultisigController {
n?: number
addresses?: string[]
alias?: string
+ startBlockNumber?: number
}) {
+ const config = await this.#multisigService.getMultisigConfigById(params.id)
const result = await this.#multisigService.updateMultisigConfig(params)
+ const network = NetworksService.getInstance().getCurrent()
+ if (params.startBlockNumber && network.type === NetworkType.Light) {
+ if (config?.startBlockNumber !== undefined && config.startBlockNumber > params.startBlockNumber) {
+ // if set small than last, reset by set_script
+ this.resetMultisigSync(config, params.startBlockNumber)
+ }
+ // if it's light client, restart queue task
+ MultisigConfigDbChangedSubject.getSubject().next('UpdateStartBlockNumber')
+ }
return {
status: ResponseCode.Success,
result,
diff --git a/packages/neuron-wallet/src/controllers/wallets.ts b/packages/neuron-wallet/src/controllers/wallets.ts
index 29bff5030e..db66030bfa 100644
--- a/packages/neuron-wallet/src/controllers/wallets.ts
+++ b/packages/neuron-wallet/src/controllers/wallets.ts
@@ -168,8 +168,8 @@ export default class WalletsController {
const keystoreObject = Keystore.fromJson(keystore)
const masterPrivateKey = keystoreObject.extendedPrivateKey(password)
const masterKeychain = new Keychain(
- Buffer.from(masterPrivateKey.privateKey, 'hex'),
- Buffer.from(masterPrivateKey.chainCode, 'hex')
+ Buffer.from(bytes.bytify(masterPrivateKey.privateKey)),
+ Buffer.from(bytes.bytify(masterPrivateKey.chainCode))
)
const accountKeychain = masterKeychain.derivePath(AccountExtendedPublicKey.ckbAccountPath)
const accountExtendedPublicKey = new AccountExtendedPublicKey(
diff --git a/packages/neuron-wallet/src/database/chain/entities/multisig-config.ts b/packages/neuron-wallet/src/database/chain/entities/multisig-config.ts
index 698be44a0f..3e62b73e5b 100644
--- a/packages/neuron-wallet/src/database/chain/entities/multisig-config.ts
+++ b/packages/neuron-wallet/src/database/chain/entities/multisig-config.ts
@@ -29,6 +29,9 @@ export default class MultisigConfig {
@Column()
lastestBlockNumber: string = ''
+ @Column()
+ startBlockNumber?: number
+
public static fromModel(model: MultisigConfigModel): MultisigConfig {
const multisigConfig = new MultisigConfig()
diff --git a/packages/neuron-wallet/src/database/chain/migrations/1651820157100-RemoveAddressesMultisigConfig.ts b/packages/neuron-wallet/src/database/chain/migrations/1651820157100-RemoveAddressesMultisigConfig.ts
index 2d8469aff9..279acba979 100644
--- a/packages/neuron-wallet/src/database/chain/migrations/1651820157100-RemoveAddressesMultisigConfig.ts
+++ b/packages/neuron-wallet/src/database/chain/migrations/1651820157100-RemoveAddressesMultisigConfig.ts
@@ -8,7 +8,9 @@ export class RemoveAddressesMultisigConfig1651820157100 implements MigrationInte
public async up(queryRunner: QueryRunner): Promise {
await queryRunner.renameColumn('multisig_config', 'addresses', 'blake160s')
await queryRunner.dropColumn('multisig_config', 'fullpayload')
- const configList = await queryRunner.manager.find(MultisigConfig)
+ // after add a column for multisig_config here will throw exception if use `queryRunner.manager.find(MultisigConfig)`
+ // so it's better to use query to find the items
+ const configList: MultisigConfig[] = await queryRunner.manager.query('select * from multisig_config')
const updated = configList.map(v => {
v.blake160s = v.blake160s.map(v => addressToScript(v).args)
return v
diff --git a/packages/neuron-wallet/src/database/chain/migrations/1681360188494-AddTypeSyncProgress.ts b/packages/neuron-wallet/src/database/chain/migrations/1681360188494-AddTypeSyncProgress.ts
index e5dfeabc7e..3958f3e287 100644
--- a/packages/neuron-wallet/src/database/chain/migrations/1681360188494-AddTypeSyncProgress.ts
+++ b/packages/neuron-wallet/src/database/chain/migrations/1681360188494-AddTypeSyncProgress.ts
@@ -15,10 +15,9 @@ export class AddTypeSyncProgress1681360188494 implements MigrationInterface {
default: SyncAddressType.Default,
}))
await queryRunner.createIndex("sync_progress", new TableIndex({ columnNames: ["addressType"] }))
- const multisigConfigs = await queryRunner.connection
- .getRepository(MultisigConfig)
- .createQueryBuilder()
- .getMany()
+ // after add a column for multisig_config here will throw exception if use `queryRunner.manager.find(MultisigConfig)`
+ // so it's better to use query to find the items
+ const multisigConfigs: MultisigConfig[] = await queryRunner.manager.query('select * from multisig_config')
const scriptHashes = multisigConfigs.map(v => scriptToHash(Multisig.getMultisigScript(v.blake160s, v.r, v.m, v.n)))
await queryRunner.query(`UPDATE sync_progress set addressType=1 where hash in (${scriptHashes.map(v => `'${v}'`).join(',')})`)
}
diff --git a/packages/neuron-wallet/src/database/chain/migrations/1702781527414-RenameSyncProgress.ts b/packages/neuron-wallet/src/database/chain/migrations/1702781527414-RenameSyncProgress.ts
index 4a6c4b78d8..7ef43299d1 100644
--- a/packages/neuron-wallet/src/database/chain/migrations/1702781527414-RenameSyncProgress.ts
+++ b/packages/neuron-wallet/src/database/chain/migrations/1702781527414-RenameSyncProgress.ts
@@ -1,21 +1,18 @@
-import {MigrationInterface, QueryRunner, TableColumn} from "typeorm";
+import {MigrationInterface, QueryRunner} from "typeorm";
export class RenameSyncProgress1702781527414 implements MigrationInterface {
name = 'RenameSyncProgress1702781527414'
public async up(queryRunner: QueryRunner): Promise {
- await queryRunner.renameColumn('sync_progress', 'blockStartNumber', 'localSavedBlockNumber')
- await queryRunner.renameColumn('sync_progress', 'blockEndNumber', 'syncedBlockNumber')
- await queryRunner.addColumn('sync_progress', new TableColumn({
- name: 'lightStartBlockNumber',
- type: 'integer',
- default: 0
- }))
+ // the typeorm renameColumn will throw an exception about drop indexer when rename or add column
+ await queryRunner.query('ALTER TABLE "sync_progress" RENAME "blockStartNumber" to "localSavedBlockNumber"')
+ await queryRunner.query('ALTER TABLE "sync_progress" RENAME "blockEndNumber" to "syncedBlockNumber"')
+ await queryRunner.query(`ALTER TABLE "sync_progress" ADD COLUMN "lightStartBlockNumber" integer DEFAULT 0;`)
}
public async down(queryRunner: QueryRunner): Promise {
- await queryRunner.renameColumn('sync_progress', 'localSavedBlockNumber', 'blockStartNumber')
- await queryRunner.renameColumn('sync_progress', 'syncedBlockNumber', 'blockEndNumber')
- }
+ await queryRunner.query('ALTER TABLE "sync_progress" RENAME "localSavedBlockNumber" to "blockStartNumber"')
+ await queryRunner.query('ALTER TABLE "sync_progress" RENAME "syncedBlockNumber" to "blockEndNumber"')
+ }
}
diff --git a/packages/neuron-wallet/src/database/chain/migrations/1716539079505-AddStartBlockNumber.ts b/packages/neuron-wallet/src/database/chain/migrations/1716539079505-AddStartBlockNumber.ts
new file mode 100644
index 0000000000..c1bdb527c5
--- /dev/null
+++ b/packages/neuron-wallet/src/database/chain/migrations/1716539079505-AddStartBlockNumber.ts
@@ -0,0 +1,14 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class AddStartBlockNumber1716539079505 implements MigrationInterface {
+ name = 'AddStartBlockNumber1716539079505'
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "multisig_config" ADD COLUMN "startBlockNumber" integer;`)
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "multisig_config" DROP COLUMN "startBlockNumber";`)
+ }
+
+}
diff --git a/packages/neuron-wallet/src/database/chain/ormconfig.ts b/packages/neuron-wallet/src/database/chain/ormconfig.ts
index e49a21cad4..c3458375cd 100644
--- a/packages/neuron-wallet/src/database/chain/ormconfig.ts
+++ b/packages/neuron-wallet/src/database/chain/ormconfig.ts
@@ -68,6 +68,7 @@ import MultisigConfigSubscribe from './subscriber/multisig-config-subscriber'
import TxDescriptionSubscribe from './subscriber/tx-description-subscriber'
import SudtTokenInfoSubscribe from './subscriber/sudt-token-info-subscriber'
import AssetAccountSubscribe from './subscriber/asset-account-subscriber'
+import { AddStartBlockNumber1716539079505 } from './migrations/1716539079505-AddStartBlockNumber'
export const CONNECTION_NOT_FOUND_NAME = 'ConnectionNotFoundError'
export type ConnectionName = 'light' | 'full'
@@ -184,6 +185,7 @@ const getConnectionOptions = (genesisBlockHash: string, connectionName: Connecti
RenameSyncProgress1702781527414,
RemoveAddressInIndexerCache1704357651876,
AmendTransaction1709008125088,
+ AddStartBlockNumber1716539079505,
],
subscribers: [
AddressSubscribe,
diff --git a/packages/neuron-wallet/src/models/chain/live-cell.ts b/packages/neuron-wallet/src/models/chain/live-cell.ts
index c57fb25fed..9a7cda74a2 100644
--- a/packages/neuron-wallet/src/models/chain/live-cell.ts
+++ b/packages/neuron-wallet/src/models/chain/live-cell.ts
@@ -1,6 +1,6 @@
import Script, { ScriptHashType } from './script'
import OutPoint from './out-point'
-import { LumosCell } from '../../block-sync-renderer/sync/synchronizer'
+import { type Cell, type OutPoint as IOutPoint } from '@ckb-lumos/base'
const LUMOS_HASH_TYPE_MAP: Record = {
type: ScriptHashType.Type,
@@ -8,6 +8,8 @@ const LUMOS_HASH_TYPE_MAP: Record = {
data: ScriptHashType.Data,
}
+export type CellWithOutPoint = Cell & { outPoint: IOutPoint }
+
export default class LiveCell {
public txHash: string
public outputIndex: string
@@ -54,7 +56,7 @@ export default class LiveCell {
return undefined
}
- public static fromLumos(cell: LumosCell): LiveCell {
+ public static fromLumos(cell: CellWithOutPoint): LiveCell {
const type = cell.cellOutput.type
? new Script(
cell.cellOutput.type.codeHash,
diff --git a/packages/neuron-wallet/src/models/chain/transaction.ts b/packages/neuron-wallet/src/models/chain/transaction.ts
index 1f4a0d1223..a8942bb43c 100644
--- a/packages/neuron-wallet/src/models/chain/transaction.ts
+++ b/packages/neuron-wallet/src/models/chain/transaction.ts
@@ -82,6 +82,8 @@ export default class Transaction {
public signatures: Signatures = {}
public assetAccountType?: AssetAccountType
+ public daoCapacity?: string
+
constructor(
version: string,
cellDeps: CellDep[] = [],
@@ -106,7 +108,8 @@ export default class Transaction {
sudtInfo?: SudtInfo,
nftType?: NFTInfo,
signatures: Signatures = {},
- assetAccountType?: AssetAccountType
+ assetAccountType?: AssetAccountType,
+ daoCapacity?: string
) {
this.cellDeps = cellDeps
this.headerDeps = headerDeps
@@ -133,6 +136,7 @@ export default class Transaction {
this.sudtInfo = sudtInfo
this.nftInfo = nftType
this.signatures = signatures
+ this.daoCapacity = daoCapacity
TypeCheckerUtils.hashChecker(...this.headerDeps, this.blockHash)
TypeCheckerUtils.numberChecker(
this.version,
@@ -171,6 +175,7 @@ export default class Transaction {
nftInfo,
signatures = {},
assetAccountType,
+ daoCapacity,
}: {
version: string
cellDeps?: CellDep[]
@@ -196,6 +201,7 @@ export default class Transaction {
nftInfo?: NFTInfo
signatures?: Signatures
assetAccountType?: AssetAccountType
+ daoCapacity?: string
}): Transaction {
return new Transaction(
version,
@@ -226,7 +232,8 @@ export default class Transaction {
sudtInfo,
nftInfo,
signatures,
- assetAccountType
+ assetAccountType,
+ daoCapacity
)
}
diff --git a/packages/neuron-wallet/src/models/subjects/multisig-config-db-changed-subject.ts b/packages/neuron-wallet/src/models/subjects/multisig-config-db-changed-subject.ts
index fc8358a5e8..cbdfd63c1f 100644
--- a/packages/neuron-wallet/src/models/subjects/multisig-config-db-changed-subject.ts
+++ b/packages/neuron-wallet/src/models/subjects/multisig-config-db-changed-subject.ts
@@ -2,7 +2,7 @@ import { ReplaySubject } from 'rxjs'
// subscribe this Subject to monitor any transaction table changes
export class MultisigConfigDbChangedSubject {
- private static subject = new ReplaySubject<'AfterInsert' | 'AfterRemove'>(100)
+ private static subject = new ReplaySubject<'AfterInsert' | 'AfterRemove' | 'UpdateStartBlockNumber'>(100)
public static getSubject() {
return MultisigConfigDbChangedSubject.subject
diff --git a/packages/neuron-wallet/src/services/ckb-runner.ts b/packages/neuron-wallet/src/services/ckb-runner.ts
index 003800312d..5eae7a91ef 100644
--- a/packages/neuron-wallet/src/services/ckb-runner.ts
+++ b/packages/neuron-wallet/src/services/ckb-runner.ts
@@ -115,8 +115,12 @@ export const startCkbNode = async () => {
listenPort = await getUsablePort(rpcPort >= listenPort ? rpcPort + 1 : listenPort)
updateToml(path.join(SettingsService.getInstance().getNodeDataPath(), 'ckb.toml'), {
- rpc: `listen_address = "127.0.0.1:${rpcPort}"`,
- network: `listen_addresses = ["/ip4/0.0.0.0/tcp/${listenPort}"]`,
+ rpc: {
+ listen_address: `"127.0.0.1:${rpcPort}"`,
+ },
+ network: {
+ listen_addresses: `["/ip4/0.0.0.0/tcp/${listenPort}"]`,
+ },
})
const options = ['run', '-C', SettingsService.getInstance().getNodeDataPath(), '--indexer']
const stdio: (StdioNull | StdioPipe)[] = ['ignore', 'pipe', 'pipe']
diff --git a/packages/neuron-wallet/src/services/hardware/hardware.ts b/packages/neuron-wallet/src/services/hardware/hardware.ts
index 9d28825752..fc0b1f9641 100644
--- a/packages/neuron-wallet/src/services/hardware/hardware.ts
+++ b/packages/neuron-wallet/src/services/hardware/hardware.ts
@@ -140,7 +140,6 @@ export abstract class Hardware {
public abstract signMessage(path: string, messageHex: string): Promise
public abstract disconnect(): Promise
public abstract getAppVersion(): Promise
- public abstract getFirmwareVersion?(): Promise
public abstract signTransaction(
walletID: string,
tx: Transaction,
diff --git a/packages/neuron-wallet/src/services/hardware/ledger.ts b/packages/neuron-wallet/src/services/hardware/ledger.ts
index a3f6fca5eb..d22bb8713c 100644
--- a/packages/neuron-wallet/src/services/hardware/ledger.ts
+++ b/packages/neuron-wallet/src/services/hardware/ledger.ts
@@ -12,6 +12,20 @@ import logger from '../../utils/logger'
import NetworksService from '../../services/networks'
import { generateRPC } from '../../utils/ckb-rpc'
+const UNCOMPRESSED_KEY_LENGTH = 130
+const compressPublicKey = (key: string) => {
+ if (key.length !== UNCOMPRESSED_KEY_LENGTH) {
+ return key
+ }
+
+ const publicKey = Buffer.from(key, 'hex')
+ const compressedPublicKey = Buffer.alloc(33)
+ // '03' for odd value, '02' for even value
+ .fill(publicKey[64] & 1 ? '03' : '02', 0, 1, 'hex')
+ .fill(publicKey.subarray(1, 33), 1, 33)
+ return compressedPublicKey.toString('hex')
+}
+
export default class Ledger extends Hardware {
private ledgerCKB: LedgerCKB | null = null
private transport: Transport | null = null
@@ -41,8 +55,9 @@ export default class Ledger extends Hardware {
public async getExtendedPublicKey(): Promise {
const { public_key, chain_code } = await this.ledgerCKB!.getWalletExtendedPublicKey(this.defaultPath)
+ // The ledger wallet's public key is unzipped, so zip it to 33 bytes https://en.bitcoin.it/wiki/BIP_0032 serializes the coordinate pair P
return {
- publicKey: public_key,
+ publicKey: compressPublicKey(public_key),
chainCode: chain_code,
}
}
@@ -89,16 +104,6 @@ export default class Ledger extends Hardware {
return conf!.version
}
- async getFirmwareVersion(): Promise {
- const res: Buffer = await this.transport!.send(0xe0, 0x01, 0x00, 0x00)!
- const byteArray = [...res]
- const data = byteArray.slice(0, byteArray.length - 2)
- const versionLength = data[4]
- const version = Buffer.from(data.slice(5, 5 + versionLength)).toString()
-
- return version
- }
-
async getPublicKey(path: string) {
const networkService = NetworksService.getInstance()
const isTestnet = !networkService.isMainnet()
diff --git a/packages/neuron-wallet/src/services/light-runner.ts b/packages/neuron-wallet/src/services/light-runner.ts
index 1c05fbf38e..da93dd39d2 100644
--- a/packages/neuron-wallet/src/services/light-runner.ts
+++ b/packages/neuron-wallet/src/services/light-runner.ts
@@ -81,6 +81,7 @@ export class CKBLightRunner extends NodeRunner {
protected binaryName: string = 'ckb-light-client'
protected logStream: Map = new Map()
protected _port: number = 9000
+ protected listenPort: number = 8118
static getInstance(): CKBLightRunner {
if (!CKBLightRunner.instance) {
@@ -117,13 +118,22 @@ export class CKBLightRunner extends NodeRunner {
async updateConfig() {
const usablePort = await getUsablePort(this._port)
+ const listenPort = await getUsablePort(usablePort >= this._port ? this.listenPort + 1 : this.listenPort)
this._port = usablePort
+ this.listenPort = listenPort
const storePath = path.join(SettingsService.getInstance().getNodeDataPath(), './store')
const networkPath = path.join(SettingsService.getInstance().getNodeDataPath(), './network')
updateToml(this.configFile, {
- store: `path = "${this.platform() === 'win' ? storePath.replace(/\\/g, '\\\\') : storePath}"`,
- network: `path = "${this.platform() === 'win' ? networkPath.replace(/\\/g, '\\\\') : networkPath}"`,
- rpc: `listen_address = "127.0.0.1:${usablePort}"`,
+ store: {
+ path: `"${this.platform() === 'win' ? storePath.replace(/\\/g, '\\\\') : storePath}"`,
+ },
+ network: {
+ path: `"${this.platform() === 'win' ? networkPath.replace(/\\/g, '\\\\') : networkPath}"`,
+ listen_addresses: `["/ip4/0.0.0.0/tcp/${listenPort}"]`,
+ },
+ rpc: {
+ listen_address: `"127.0.0.1:${usablePort}"`,
+ },
})
}
diff --git a/packages/neuron-wallet/src/services/live-cell-service.ts b/packages/neuron-wallet/src/services/live-cell-service.ts
index 4b7766d3db..3fe38814a6 100644
--- a/packages/neuron-wallet/src/services/live-cell-service.ts
+++ b/packages/neuron-wallet/src/services/live-cell-service.ts
@@ -1,7 +1,7 @@
import Script from '../models/chain/script'
-import LiveCell from '../models/chain/live-cell'
+import LiveCell, { CellWithOutPoint } from '../models/chain/live-cell'
import { queryIndexer } from '../block-sync-renderer/index'
-import { LumosCell, LumosCellQuery } from '../block-sync-renderer/sync/synchronizer'
+import { type QueryOptions } from '@ckb-lumos/base'
export default class LiveCellService {
private static instance: LiveCellService
@@ -20,14 +20,14 @@ export default class LiveCellService {
lock: Script | null,
type: Script | null,
data: string | null
- ): Promise {
+ ): Promise {
if (!lock && !type) {
throw new Error('at least one parameter is required')
}
- const query: LumosCellQuery = { lock, type, data }
- const liveCells: LumosCell[] = await queryIndexer(query)
- return liveCells
+ const query = { lock, type, data } as QueryOptions
+ const liveCells = await queryIndexer(query)
+ return liveCells as CellWithOutPoint[]
}
public async getOneByLockScriptAndTypeScript(lock: Script | null, type: Script | null) {
diff --git a/packages/neuron-wallet/src/services/multisig.ts b/packages/neuron-wallet/src/services/multisig.ts
index 5f97cd3b3a..2f3da9467f 100644
--- a/packages/neuron-wallet/src/services/multisig.ts
+++ b/packages/neuron-wallet/src/services/multisig.ts
@@ -41,6 +41,7 @@ export default class MultisigService {
n?: number
blake160s?: string[]
alias?: string
+ startBlockNumber?: number
}) {
const result = await getConnection()
.getRepository(MultisigConfig)
@@ -52,19 +53,15 @@ export default class MultisigService {
if (!result) {
throw new MultisigConfigNotExistError()
}
- await getConnection()
- .createQueryBuilder()
- .update(MultisigConfig)
- .set({
- alias: params.alias ?? result.alias,
- walletId: params.walletId ?? result.walletId,
- r: params.r ?? result.r,
- m: params.m ?? result.m,
- n: params.n ?? result.n,
- blake160s: params.blake160s ?? result.blake160s,
- })
- .where('id = :id', { id: params.id })
- .execute()
+ await getConnection().getRepository(MultisigConfig).update(params.id, {
+ alias: params.alias,
+ walletId: params.walletId,
+ r: params.r,
+ m: params.m,
+ n: params.n,
+ blake160s: params.blake160s,
+ startBlockNumber: params.startBlockNumber,
+ })
return { ...result, ...params }
}
@@ -77,6 +74,16 @@ export default class MultisigService {
return result
}
+ async getMultisigConfigById(id: number) {
+ return getConnection()
+ .getRepository(MultisigConfig)
+ .createQueryBuilder()
+ .where({
+ id,
+ })
+ .getOne()
+ }
+
async deleteConfig(id: number) {
const config = await getConnection()
.getRepository(MultisigConfig)
@@ -342,6 +349,7 @@ export default class MultisigService {
script: Multisig.getMultisigScript(v.blake160s, v.r, v.m, v.n),
addressType: SyncAddressType.Multisig,
scriptType: 'lock' as CKBRPC.ScriptType,
+ startBlockNumber: v.startBlockNumber,
}))
}
}
diff --git a/packages/neuron-wallet/src/services/settings.ts b/packages/neuron-wallet/src/services/settings.ts
index d482390249..f836ba5e0e 100644
--- a/packages/neuron-wallet/src/services/settings.ts
+++ b/packages/neuron-wallet/src/services/settings.ts
@@ -88,7 +88,7 @@ export default class SettingsService extends Store {
private generateEncryptString(str: string) {
if (safeStorage.isEncryptionAvailable()) {
- return safeStorage.encryptString(str).toString('utf-8')
+ return safeStorage.encryptString(str).toString('hex')
}
const hash = crypto.createHash('sha256')
hash.update(str)
@@ -108,6 +108,9 @@ export default class SettingsService extends Store {
}
verifyLockWindowPassword(password: string) {
+ if (safeStorage.isEncryptionAvailable()) {
+ return safeStorage.decryptString(Buffer.from(this.lockWindowInfo.encryptedPassword!, 'hex')) === password
+ }
const encryptedPassword = this.generateEncryptString(password)
return SettingsService.getInstance().lockWindowInfo.encryptedPassword === encryptedPassword
}
diff --git a/packages/neuron-wallet/src/services/sign-message.ts b/packages/neuron-wallet/src/services/sign-message.ts
index 8d3bfd562d..aeaf32dca7 100644
--- a/packages/neuron-wallet/src/services/sign-message.ts
+++ b/packages/neuron-wallet/src/services/sign-message.ts
@@ -6,6 +6,7 @@ import { ec as EC } from 'elliptic'
import { AddressNotFound } from '../exceptions'
import HardwareWalletService from './hardware'
import AddressParser from '../models/address-parser'
+import { bytes } from '@ckb-lumos/codec'
export default class SignMessage {
static GENERATE_COUNT = 100
@@ -91,8 +92,8 @@ export default class SignMessage {
private static getPrivateKey(wallet: Wallet, path: string, password: string): string {
const masterPrivateKey = wallet.loadKeystore().extendedPrivateKey(password)
const masterKeychain = new Keychain(
- Buffer.from(masterPrivateKey.privateKey, 'hex'),
- Buffer.from(masterPrivateKey.chainCode, 'hex')
+ Buffer.from(bytes.bytify(masterPrivateKey.privateKey)),
+ Buffer.from(bytes.bytify(masterPrivateKey.chainCode))
)
return `0x${masterKeychain.derivePath(path).privateKey.toString('hex')}`
diff --git a/packages/neuron-wallet/src/services/sync-progress.ts b/packages/neuron-wallet/src/services/sync-progress.ts
index 54839896f2..1c46bdac31 100644
--- a/packages/neuron-wallet/src/services/sync-progress.ts
+++ b/packages/neuron-wallet/src/services/sync-progress.ts
@@ -86,15 +86,15 @@ export default class SyncProgressService {
return result
}
- static async getCurrentWalletMinSyncedBlockNumber() {
+ static async getCurrentWalletMinSyncedBlockNumber(addressType: SyncAddressType = SyncAddressType.Default) {
const currentWallet = WalletService.getInstance().getCurrent()
const item = await getConnection()
.getRepository(SyncProgress)
.createQueryBuilder()
.where({
delete: false,
- addressType: SyncAddressType.Default,
- ...(currentWallet ? { walletId: currentWallet.id } : {}),
+ addressType,
+ ...(currentWallet && addressType === SyncAddressType.Default ? { walletId: currentWallet.id } : {}),
})
.orderBy('syncedBlockNumber', 'ASC')
.getOne()
@@ -144,4 +144,17 @@ export default class SyncProgressService {
addressType: SyncAddressType.Default,
})
}
+
+ static async resetMultisigSync(hash: string, startBlockNumber: number) {
+ await getConnection()
+ .createQueryBuilder()
+ .update(SyncProgress)
+ .set({
+ localSavedBlockNumber: startBlockNumber,
+ lightStartBlockNumber: startBlockNumber,
+ syncedBlockNumber: startBlockNumber,
+ })
+ .where({ hash })
+ .execute()
+ }
}
diff --git a/packages/neuron-wallet/src/services/tx/transaction-service.ts b/packages/neuron-wallet/src/services/tx/transaction-service.ts
index eb5cf93dd3..8b43057ed9 100644
--- a/packages/neuron-wallet/src/services/tx/transaction-service.ts
+++ b/packages/neuron-wallet/src/services/tx/transaction-service.ts
@@ -256,6 +256,7 @@ export class TransactionsService {
.addSelect('input.transactionHash', 'transactionHash')
.addSelect('input.outPointTxHash', 'outPointTxHash')
.addSelect('input.outPointIndex', 'outPointIndex')
+ .addSelect('input.data', 'data')
.where(
`
input.transactionHash IN (:...txHashes) AND
@@ -266,7 +267,13 @@ export class TransactionsService {
walletId: params.walletID,
}
)
- .getRawMany()
+ .getRawMany<{
+ capacity: string
+ transactionHash: string
+ outPointTxHash: string
+ outPointIndex: string
+ data: string
+ }>()
const outputs = await connection
.getRepository(OutputEntity)
@@ -284,7 +291,7 @@ export class TransactionsService {
walletId: params.walletID,
}
)
- .getRawMany()
+ .getRawMany<{ capacity: string; transactionHash: string; daoData: string }>()
const assetAccountInputs = await connection
.getRepository(InputEntity)
@@ -373,13 +380,17 @@ export class TransactionsService {
).filter(o => inputPreviousTxHashes.includes(o.txHash))
const sums = new Map()
- const daoFlag = new Map()
+ const daoInfo = new Map()
outputs.map(o => {
const s = sums.get(o.transactionHash) || BigInt(0)
sums.set(o.transactionHash, s + BigInt(o.capacity))
if (o.daoData) {
- daoFlag.set(o.transactionHash, true)
+ if (daoInfo.has(o.transactionHash)) {
+ daoInfo.get(o.transactionHash)!.outputs.push(o)
+ } else {
+ daoInfo.set(o.transactionHash, { inputs: [], outputs: [o] })
+ }
}
})
@@ -391,7 +402,11 @@ export class TransactionsService {
return dc.txHash === i.outPointTxHash && dc.index === i.outPointIndex
})
if (result) {
- daoFlag.set(i.transactionHash, true)
+ if (daoInfo.has(i.transactionHash)) {
+ daoInfo.get(i.transactionHash)!.inputs.push(i)
+ } else {
+ daoInfo.set(i.transactionHash, { inputs: [i], outputs: [] })
+ }
}
})
@@ -477,6 +492,16 @@ export class TransactionsService {
nftInfo = { type: NFTType.Receive, data: receiveNFTCell.typeArgs! }
}
+ const txDaoInfo = daoInfo.get(tx.hash)
+ let daoCapacity: string | undefined
+ if (txDaoInfo) {
+ if (txDaoInfo.inputs.length && !txDaoInfo.outputs.length) {
+ daoCapacity = txDaoInfo.inputs.reduce((pre, cur) => BigInt(cur.capacity) + pre, BigInt(value)).toString()
+ } else if (!txDaoInfo.inputs.length && txDaoInfo.outputs.length) {
+ daoCapacity = `-${txDaoInfo.outputs.reduce((pre, cur) => BigInt(cur.capacity) + pre, BigInt(0)).toString()}`
+ }
+ }
+
return Transaction.fromObject({
timestamp: tx.timestamp,
value: value.toString(),
@@ -484,7 +509,7 @@ export class TransactionsService {
version: tx.version,
type: txType,
assetAccountType: assetAccountType,
- nervosDao: daoFlag.get(tx.hash!),
+ nervosDao: !!txDaoInfo,
status: tx.status,
description: tx.description,
createdAt: tx.createdAt,
@@ -492,6 +517,7 @@ export class TransactionsService {
blockNumber: tx.blockNumber,
sudtInfo: sudtInfo,
nftInfo: nftInfo,
+ daoCapacity,
})
})
)
diff --git a/packages/neuron-wallet/src/utils/toml.ts b/packages/neuron-wallet/src/utils/toml.ts
index b0e724513f..97a57eef78 100644
--- a/packages/neuron-wallet/src/utils/toml.ts
+++ b/packages/neuron-wallet/src/utils/toml.ts
@@ -1,7 +1,11 @@
import fs from 'fs'
import path from 'path'
-export function updateToml(filePath: string, updateValue: Record, newFilePath?: string) {
+export function updateToml(
+ filePath: string,
+ updateValue: Record>,
+ newFilePath?: string
+) {
const values = fs.readFileSync(filePath).toString().split('\n')
let field: string | undefined = undefined
const newValues = values.map(v => {
@@ -14,9 +18,15 @@ export function updateToml(filePath: string, updateValue: Record
return v
}
if (field && updateValue[field]) {
- const newLine = updateValue[field]
- field = undefined
- return newLine
+ const equalIndex = v.indexOf('=')
+ if (equalIndex !== -1) {
+ const stringBeforeEqual = v.slice(0, equalIndex)
+ const key = stringBeforeEqual.trim()
+ if (updateValue[field][key]) {
+ const newLine = `${stringBeforeEqual}= ${updateValue[field][key]}`
+ return newLine
+ }
+ }
}
return v
})
diff --git a/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts
index b4f2cd19fd..b4af6a23a4 100644
--- a/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts
+++ b/packages/neuron-wallet/tests/block-sync-renderer/full-synchronizer.test.ts
@@ -87,14 +87,12 @@ describe('unit tests for IndexerConnector', () => {
})
describe('#constructor', () => {
- const STUB_URI = 'stub_uri'
-
describe('when init with indexer folder path', () => {
beforeEach(() => {
- new stubbedFullSynchronizer([], nodeUrl, STUB_URI)
+ new stubbedFullSynchronizer([], nodeUrl)
})
it('inits lumos indexer with a node url and indexer folder path', () => {
- expect(stubbedIndexerConstructor).toHaveBeenCalledWith(nodeUrl, STUB_URI)
+ expect(stubbedIndexerConstructor).toHaveBeenCalledWith(nodeUrl)
})
})
describe('when init without indexer folder path', () => {
@@ -102,7 +100,7 @@ describe('unit tests for IndexerConnector', () => {
new stubbedFullSynchronizer([], nodeUrl)
})
it('inits mercury indexer with a node url and a default port', () => {
- expect(stubbedIndexerConstructor).toHaveBeenCalledWith(nodeUrl, STUB_URI)
+ expect(stubbedIndexerConstructor).toHaveBeenCalledWith(nodeUrl)
})
})
})
diff --git a/packages/neuron-wallet/tests/block-sync-renderer/index/createBlockSyncTask.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/index/createBlockSyncTask.test.ts
index 61da50c476..6f04520d7e 100644
--- a/packages/neuron-wallet/tests/block-sync-renderer/index/createBlockSyncTask.test.ts
+++ b/packages/neuron-wallet/tests/block-sync-renderer/index/createBlockSyncTask.test.ts
@@ -75,9 +75,9 @@ describe(`Create block sync task`, () => {
message: {
addressMetas: STUB_ADDRESS_METAS,
genesisHash: STUB_NETWORK.genesisHash,
- indexerUrl: STUB_NETWORK.remote,
nodeType: NetworkType.Normal,
url: STUB_NETWORK.remote,
+ syncMultisig: false,
},
})
})
diff --git a/packages/neuron-wallet/tests/block-sync-renderer/light-synchronizer.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/light-synchronizer.test.ts
index ccd7ee549e..0b8d0b9531 100644
--- a/packages/neuron-wallet/tests/block-sync-renderer/light-synchronizer.test.ts
+++ b/packages/neuron-wallet/tests/block-sync-renderer/light-synchronizer.test.ts
@@ -24,6 +24,7 @@ const schedulerWaitMock = jest.fn()
const getMultisigConfigForLightMock = jest.fn()
const walletGetCurrentMock = jest.fn()
const walletGetAllMock = jest.fn()
+const updateBlockStartNumberMock = jest.fn()
function mockReset() {
getSyncStatusMock.mockReset()
@@ -46,6 +47,8 @@ function mockReset() {
removeByHashesAndAddressType.mockReset()
walletGetCurrentMock.mockReset()
walletGetAllMock.mockReset()
+
+ updateBlockStartNumberMock.mockReset()
}
jest.mock('../../src/services/sync-progress', () => {
@@ -123,12 +126,15 @@ describe('test light synchronizer', () => {
await connect.initSyncProgress()
expect(getScriptsMock).toBeCalledTimes(0)
})
- it('append multisig script', async () => {
+ it('sync multisig config', async () => {
getScriptsMock.mockResolvedValue([])
const connect = new LightSynchronizer([], '')
getOtherTypeSyncBlockNumberMock.mockResolvedValueOnce({})
+ getMultisigConfigForLightMock.mockResolvedValueOnce([
+ { walletId: 'walletId', script, addressType: 1, scriptType: 'lock' },
+ ])
//@ts-ignore
- await connect.initSyncProgress([{ walletId: 'walletId', script, addressType: 1, scriptType: 'lock' }])
+ await connect.initMultisigSyncProgress()
expect(getScriptsMock).toBeCalledTimes(1)
expect(setScriptsMock).toHaveBeenNthCalledWith(
1,
@@ -138,6 +144,7 @@ describe('test light synchronizer', () => {
})
it('when syncing script in the local DB', async () => {
getScriptsMock.mockResolvedValue([{ script, blockNumber: '0xaa' }])
+ walletGetAllMock.mockReturnValue([{ id: 'walletId' }])
getExistingSyncArgsesMock.mockResolvedValue(new Set([script.args]))
const addressMeta = AddressMeta.fromObject({
walletId: 'walletId',
@@ -187,6 +194,7 @@ describe('test light synchronizer', () => {
})
it('when syncing script not in the local DB', async () => {
getScriptsMock.mockResolvedValue([{ script, blockNumber: '0xaa' }])
+ walletGetAllMock.mockReturnValue([{ id: 'walletId' }])
getExistingSyncArgsesMock.mockResolvedValue(new Set())
const addressMeta = AddressMeta.fromObject({
walletId: 'walletId',
@@ -256,6 +264,7 @@ describe('test light synchronizer', () => {
addressType: 0,
blake160: script.args,
})
+ walletGetAllMock.mockReturnValue([{ id: 'walletId' }])
getWalletMinLocalSavedBlockNumberMock.mockResolvedValue({ walletId: 170 })
const connect = new LightSynchronizer([addressMeta], '')
//@ts-ignore
@@ -367,6 +376,152 @@ describe('test light synchronizer', () => {
)
expect(setScriptsMock).toHaveBeenLastCalledWith([], 'delete')
})
+ it('when other wallet min synced block number near the current wallet', async () => {
+ walletGetCurrentMock.mockReturnValue({ id: 'walletId1' })
+ walletGetAllMock.mockReturnValue([
+ { id: 'walletId1', startBlockNumber: '0xaa' },
+ { id: 'walletId2', startBlockNumber: '0xab' },
+ ])
+ const addressMeta1 = AddressMeta.fromObject({
+ walletId: 'walletId1',
+ address,
+ path: '',
+ addressIndex: 10,
+ addressType: 0,
+ blake160: script.args,
+ })
+ const script2: Script = {
+ args: '0x403f0d4e833b2a8d372772a63facaa310dfeef93',
+ codeHash: '0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8',
+ hashType: 'type',
+ }
+ const getScriptsResult = [{ script: script2, blockNumber: '0xaa', scriptType: 'lock' }]
+ getScriptsMock.mockResolvedValue(getScriptsResult)
+ getExistingSyncArgsesMock.mockResolvedValue(new Set([script2.args]))
+ const addressMeta2 = AddressMeta.fromObject({
+ walletId: 'walletId2',
+ address,
+ path: '',
+ addressIndex: 10,
+ addressType: 0,
+ blake160: script2.args,
+ })
+ const connect = new LightSynchronizer([addressMeta1, addressMeta2], '')
+ //@ts-ignore
+ await connect.initSyncProgress()
+ expect(setScriptsMock).toHaveBeenNthCalledWith(
+ 1,
+ [
+ ...[
+ addressMeta1.generateDefaultLockScript().toSDK(),
+ addressMeta1.generateACPLockScript().toSDK(),
+ addressMeta1.generateLegacyACPLockScript().toSDK(),
+ ].map(script => ({
+ script,
+ scriptType: 'lock',
+ walletId: addressMeta1.walletId,
+ blockNumber: '0xaa',
+ })),
+ ...[
+ addressMeta2.generateDefaultLockScript().toSDK(),
+ addressMeta2.generateACPLockScript().toSDK(),
+ addressMeta2.generateLegacyACPLockScript().toSDK(),
+ ].map(script => ({
+ script,
+ scriptType: 'lock',
+ walletId: addressMeta2.walletId,
+ blockNumber: '0xab',
+ })),
+ ],
+ 'partial'
+ )
+ expect(setScriptsMock).toHaveBeenLastCalledWith([], 'delete')
+ expect(initSyncProgressMock).toBeCalledWith([
+ ...[
+ addressMeta1.generateDefaultLockScript().toSDK(),
+ addressMeta1.generateACPLockScript().toSDK(),
+ addressMeta1.generateLegacyACPLockScript().toSDK(),
+ ].map(script => ({
+ script,
+ scriptType: 'lock',
+ walletId: addressMeta1.walletId,
+ blockNumber: '0xaa',
+ })),
+ ...[
+ addressMeta2.generateDefaultLockScript().toSDK(),
+ addressMeta2.generateACPLockScript().toSDK(),
+ addressMeta2.generateLegacyACPLockScript().toSDK(),
+ ].map(script => ({
+ script,
+ scriptType: 'lock',
+ walletId: addressMeta2.walletId,
+ blockNumber: '0xab',
+ })),
+ ])
+ expect(updateSyncProgressFlagMock).toBeCalledWith(['walletId1', 'walletId2'])
+ })
+ it('when other wallet min synced block number bigger than the current wallet', async () => {
+ walletGetCurrentMock.mockReturnValue({ id: 'walletId1' })
+ walletGetAllMock.mockReturnValue([
+ { id: 'walletId1', startBlockNumber: '0xaaaa0' },
+ { id: 'walletId2', startBlockNumber: '0xab' },
+ ])
+ const addressMeta1 = AddressMeta.fromObject({
+ walletId: 'walletId1',
+ address,
+ path: '',
+ addressIndex: 10,
+ addressType: 0,
+ blake160: script.args,
+ })
+ const script2: Script = {
+ args: '0x403f0d4e833b2a8d372772a63facaa310dfeef93',
+ codeHash: '0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8',
+ hashType: 'type',
+ }
+ const getScriptsResult = [{ script: script2, blockNumber: '0xab', scriptType: 'lock' }]
+ getScriptsMock.mockResolvedValue(getScriptsResult)
+ getExistingSyncArgsesMock.mockResolvedValue(new Set([script2.args]))
+ const addressMeta2 = AddressMeta.fromObject({
+ walletId: 'walletId2',
+ address,
+ path: '',
+ addressIndex: 10,
+ addressType: 0,
+ blake160: script2.args,
+ })
+ const connect = new LightSynchronizer([addressMeta1, addressMeta2], '')
+ //@ts-ignore
+ await connect.initSyncProgress()
+ expect(setScriptsMock).toHaveBeenNthCalledWith(
+ 1,
+ [
+ addressMeta1.generateDefaultLockScript().toSDK(),
+ addressMeta1.generateACPLockScript().toSDK(),
+ addressMeta1.generateLegacyACPLockScript().toSDK(),
+ ].map(script => ({
+ script,
+ scriptType: 'lock',
+ walletId: addressMeta1.walletId,
+ blockNumber: '0xaaaa0',
+ })),
+ 'partial'
+ )
+ expect(setScriptsMock).toHaveBeenLastCalledWith(getScriptsResult, 'delete')
+ expect(initSyncProgressMock).toBeCalledWith(
+ [
+ addressMeta1.generateDefaultLockScript().toSDK(),
+ addressMeta1.generateACPLockScript().toSDK(),
+ addressMeta1.generateLegacyACPLockScript().toSDK(),
+ ].map(script => ({
+ script,
+ scriptType: 'lock',
+ walletId: addressMeta1.walletId,
+ blockNumber: '0xaaaa0',
+ }))
+ )
+ expect(updateSyncProgressFlagMock).toBeCalledWith(['walletId1', 'walletId2'])
+ })
})
describe('test initSync', () => {
@@ -428,16 +583,10 @@ describe('test light synchronizer', () => {
})
describe('#notifyCurrentBlockNumberProcessed', () => {
- const synchronizer = new LightSynchronizer([], '')
- const updateBlockStartNumberMock = jest.fn()
- beforeAll(() => {
+ it('last process block number finish', async () => {
+ const synchronizer = new LightSynchronizer([], '')
// @ts-ignore private property
synchronizer.updateBlockStartNumber = updateBlockStartNumberMock
- })
- beforeEach(() => {
- updateBlockStartNumberMock.mockReset()
- })
- it('last process block number finish', async () => {
// @ts-ignore private property
synchronizer.processingBlockNumber = '0xaa'
getCurrentWalletMinSyncedBlockNumberMock.mockResolvedValueOnce(100)
@@ -447,6 +596,9 @@ describe('test light synchronizer', () => {
expect(updateBlockStartNumberMock).toBeCalledWith(100)
})
it('not last process block number finish', async () => {
+ const synchronizer = new LightSynchronizer([], '')
+ // @ts-ignore private property
+ synchronizer.updateBlockStartNumber = updateBlockStartNumberMock
// @ts-ignore private property
synchronizer.processingBlockNumber = undefined
await synchronizer.notifyCurrentBlockNumberProcessed('0xaa')
diff --git a/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts
index c3c1e7e325..9836446cf2 100644
--- a/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts
+++ b/packages/neuron-wallet/tests/block-sync-renderer/synchronizer.test.ts
@@ -1,8 +1,9 @@
import { scriptToAddress } from '../../src/utils/scriptAndAddress'
import { AddressType } from '@ckb-lumos/hd'
+import { QueryOptions, type Cell } from '@ckb-lumos/base'
import { Address, AddressVersion } from '../../src/models/address'
import SystemScriptInfo from '../../src/models/system-script-info'
-import { Synchronizer, type LumosCell, type LumosCellQuery } from '../../src/block-sync-renderer/sync/synchronizer'
+import { Synchronizer } from '../../src/block-sync-renderer/sync/synchronizer'
import AddressMeta from '../../src/database/address/meta'
import IndexerTxHashCache from '../../src/database/chain/entities/indexer-tx-hash-cache'
import { ScriptHashType } from '../../src/models/chain/script'
@@ -110,22 +111,18 @@ describe('unit tests for IndexerConnector', () => {
})
describe('#constructor', () => {
- const STUB_URI = 'stub_uri'
-
it('inits lumos indexer with a node url and indexer folder path', () => {
new TestSynchronizer({
addresses: [],
nodeUrl,
- indexerUrl: STUB_URI,
})
- expect(stubbedIndexerConstructor).toHaveBeenCalledWith(nodeUrl, STUB_URI)
+ expect(stubbedIndexerConstructor).toHaveBeenCalledWith(nodeUrl)
})
it('init with addresses', () => {
const synchronizer = new TestSynchronizer({
addresses: [addressObj1, addressObj2],
nodeUrl,
- indexerUrl: STUB_URI,
})
expect(synchronizer.getAddressesByWalletId().get(walletId1)?.[0]).toStrictEqual(
AddressMeta.fromObject(addressObj1)
@@ -140,7 +137,6 @@ describe('unit tests for IndexerConnector', () => {
const synchronizer = new TestSynchronizer({
addresses: [addressObj1, addressObj2],
nodeUrl,
- indexerUrl: '',
})
it('no cached tx', async () => {
stubbedNextUnprocessedTxsGroupedByBlockNumberFn.mockResolvedValue([])
@@ -178,7 +174,6 @@ describe('unit tests for IndexerConnector', () => {
const synchronizer = new TestSynchronizer({
addresses: [addressObj1, addressObj2],
nodeUrl,
- indexerUrl: '',
})
synchronizer.blockTipsSubject.subscribe(stubbedBlockTipsSubscribe)
@@ -220,10 +215,11 @@ describe('unit tests for IndexerConnector', () => {
})
describe('#getLiveCellsByScript', () => {
- let fakeCell1: LumosCell, fakeCell2: LumosCell
- let cells: LumosCell[]
+ let fakeCell1: Cell, fakeCell2: Cell
+ let cells: Cell[]
fakeCell1 = {
+ data: '0x',
blockHash: '0x',
outPoint: {
txHash: '0x',
@@ -244,6 +240,7 @@ describe('unit tests for IndexerConnector', () => {
},
}
fakeCell2 = {
+ data: '0x',
blockHash: '0x',
outPoint: {
txHash: '0x',
@@ -257,7 +254,7 @@ describe('unit tests for IndexerConnector', () => {
args: '0x2',
},
type: {
- hashType: 'lock',
+ hashType: 'data',
codeHash: '0xcode',
args: '0x2',
},
@@ -268,11 +265,10 @@ describe('unit tests for IndexerConnector', () => {
const synchronizer = new TestSynchronizer({
addresses: [addressObj1, addressObj2],
nodeUrl,
- indexerUrl: '',
})
describe('when success', () => {
- const query: LumosCellQuery = {
+ const query = {
lock: {
hashType: ScriptHashType.Data,
codeHash: '0xcode',
@@ -283,7 +279,6 @@ describe('unit tests for IndexerConnector', () => {
codeHash: '0xcode',
args: '0x',
},
- data: null,
}
beforeEach(async () => {
@@ -298,14 +293,14 @@ describe('unit tests for IndexerConnector', () => {
it('transform the query parameter', () => {
expect(stubbedCellCollectorConstructor.mock.calls[0][1]).toEqual({
lock: {
- hashType: query.lock!.hashType,
- codeHash: query.lock!.codeHash,
- args: query.lock!.args,
+ hashType: query.lock.hashType,
+ codeHash: query.lock.codeHash,
+ args: query.lock.args,
},
type: {
- hashType: query.type!.hashType,
- codeHash: query.type!.codeHash,
- args: query.type!.args,
+ hashType: query.type.hashType,
+ codeHash: query.type.codeHash,
+ args: query.type.args,
},
data: 'any',
})
@@ -316,7 +311,7 @@ describe('unit tests for IndexerConnector', () => {
})
})
describe('when handling concurrent requests', () => {
- const query1: LumosCellQuery = {
+ const query1: QueryOptions = {
lock: {
hashType: ScriptHashType.Data,
codeHash: '0xcode',
@@ -327,9 +322,8 @@ describe('unit tests for IndexerConnector', () => {
codeHash: '0xcode',
args: '0x1',
},
- data: null,
}
- const query2: LumosCellQuery = {
+ const query2: QueryOptions = {
lock: {
hashType: ScriptHashType.Type,
codeHash: '0xcode',
@@ -340,7 +334,6 @@ describe('unit tests for IndexerConnector', () => {
codeHash: '0xcode',
args: '0x2',
},
- data: null,
}
const results: unknown[] = []
@@ -401,7 +394,7 @@ describe('unit tests for IndexerConnector', () => {
it('throws error', async () => {
let err
try {
- await synchronizer.getLiveCellsByScript({ lock: null, type: null, data: null })
+ await synchronizer.getLiveCellsByScript({})
} catch (error) {
err = error
}
diff --git a/packages/neuron-wallet/tests/block-sync-renderer/task.test.ts b/packages/neuron-wallet/tests/block-sync-renderer/task.test.ts
index 413e782d13..706f11482f 100644
--- a/packages/neuron-wallet/tests/block-sync-renderer/task.test.ts
+++ b/packages/neuron-wallet/tests/block-sync-renderer/task.test.ts
@@ -6,7 +6,6 @@ const STUB_START_MESSAGE = {
genesisHash: 'stub_genesis_hash',
url: 'stub_url',
addressMetas: 'stub_address_metas',
- indexerUrl: 'stub_indexer_url',
nodeType: 2,
},
}
@@ -71,8 +70,8 @@ describe(`Block Sync Task`, () => {
expect(stubbedSyncQueue).toHaveBeenCalledWith(
STUB_START_MESSAGE.message.url,
STUB_START_MESSAGE.message.addressMetas,
- STUB_START_MESSAGE.message.indexerUrl,
- STUB_START_MESSAGE.message.nodeType
+ STUB_START_MESSAGE.message.nodeType,
+ undefined
)
expect(stubbedSyncQueueStart).toHaveBeenCalled()
})
diff --git a/packages/neuron-wallet/tests/models/chain/live-cell.test.ts b/packages/neuron-wallet/tests/models/chain/live-cell.test.ts
index 84a9b97830..1bc5cba2fd 100644
--- a/packages/neuron-wallet/tests/models/chain/live-cell.test.ts
+++ b/packages/neuron-wallet/tests/models/chain/live-cell.test.ts
@@ -1,6 +1,5 @@
import Script, { ScriptHashType } from '../../../src/models/chain/script'
-import { LumosCell } from '../../../src/block-sync-renderer/sync/synchronizer'
-import LiveCell from '../../../src/models/chain/live-cell'
+import LiveCell, { CellWithOutPoint } from '../../../src/models/chain/live-cell'
describe('LiveCell Test', () => {
const INITIAL_DATA = {
@@ -88,7 +87,7 @@ describe('LiveCell Test', () => {
})
describe('get cells from lumos cell', () => {
- const LUMOS_CELL: LumosCell = {
+ const LUMOS_CELL: CellWithOutPoint = {
blockHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
outPoint: {
txHash: INITIAL_DATA.txHash,
diff --git a/packages/neuron-wallet/tests/services/ckb-runner.test.ts b/packages/neuron-wallet/tests/services/ckb-runner.test.ts
index 451d9b2462..067137a946 100644
--- a/packages/neuron-wallet/tests/services/ckb-runner.test.ts
+++ b/packages/neuron-wallet/tests/services/ckb-runner.test.ts
@@ -255,8 +255,12 @@ describe('ckb runner', () => {
expect(getNodeUrl()).toBe('http://127.0.0.1:8114')
expect(getUsablePortMock).toHaveBeenLastCalledWith(8115)
expect(updateTomlMock).toBeCalledWith(path.join('/chains/mainnet', 'ckb.toml'), {
- rpc: `listen_address = "127.0.0.1:8114"`,
- network: `listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]`,
+ rpc: {
+ listen_address: `"127.0.0.1:8114"`,
+ },
+ network: {
+ listen_addresses: `["/ip4/0.0.0.0/tcp/8115"]`,
+ },
})
const promise = stopCkbNode()
stubbedCkb.emit('close')
@@ -270,8 +274,12 @@ describe('ckb runner', () => {
expect(getNodeUrl()).toBe('http://127.0.0.1:8115')
expect(getUsablePortMock).toHaveBeenLastCalledWith(8116)
expect(updateTomlMock).toBeCalledWith(path.join('/chains/mainnet', 'ckb.toml'), {
- rpc: `listen_address = "127.0.0.1:8115"`,
- network: `listen_addresses = ["/ip4/0.0.0.0/tcp/8116"]`,
+ rpc: {
+ listen_address: `"127.0.0.1:8115"`,
+ },
+ network: {
+ listen_addresses: `["/ip4/0.0.0.0/tcp/8116"]`,
+ },
})
let promise = stopCkbNode()
stubbedCkb.emit('close')
diff --git a/packages/neuron-wallet/tests/services/hardware/ledger.test.ts b/packages/neuron-wallet/tests/services/hardware/ledger.test.ts
new file mode 100644
index 0000000000..84ee4255f1
--- /dev/null
+++ b/packages/neuron-wallet/tests/services/hardware/ledger.test.ts
@@ -0,0 +1,39 @@
+import Ledger from '../../../src/services/hardware/ledger'
+
+const getWalletExtendedPublicKeyMock = jest.fn()
+
+jest.mock('hw-app-ckb', () => {
+ return function () {
+ return {
+ getWalletExtendedPublicKey: getWalletExtendedPublicKeyMock,
+ }
+ }
+})
+
+jest.mock('@ledgerhq/hw-transport-node-hid', () => ({
+ open: jest.fn(),
+}))
+
+const pk =
+ '04d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f691757b28e31be71f09f24673eed52348e58d53bcfd26f4d96ec6bf1489eab429d'
+const zipPk = '03d061e9c5891f579fd548cfd22ff29f5c642714cc7e7a9215f0071ef5a5723f69'
+
+describe('test for ledger', () => {
+ describe('test getExtendedPublicKey', () => {
+ it('if the return pk is unzip', async () => {
+ getWalletExtendedPublicKeyMock.mockResolvedValueOnce({ public_key: pk, chain_code: '0x' })
+ const ledger = new Ledger({} as any)
+ await ledger.connect()
+ const res = await ledger.getExtendedPublicKey()
+ expect(res.publicKey).toBe(zipPk)
+ })
+
+ it('if the return pk is zip', async () => {
+ getWalletExtendedPublicKeyMock.mockResolvedValueOnce({ public_key: zipPk, chain_code: '0x' })
+ const ledger = new Ledger({} as any)
+ await ledger.connect()
+ const res = await ledger.getExtendedPublicKey()
+ expect(res.publicKey).toBe(zipPk)
+ })
+ })
+})
diff --git a/packages/neuron-wallet/tests/services/light-runner.test.ts b/packages/neuron-wallet/tests/services/light-runner.test.ts
index a88ed7a1ec..1a2a2fe7ed 100644
--- a/packages/neuron-wallet/tests/services/light-runner.test.ts
+++ b/packages/neuron-wallet/tests/services/light-runner.test.ts
@@ -337,32 +337,46 @@ describe('test light runner', () => {
describe('test update config', () => {
it('port is used', async () => {
- getUsablePortMock.mockResolvedValueOnce(9001)
+ getUsablePortMock.mockResolvedValueOnce(9001).mockResolvedValueOnce(8119)
lightDataPathMock.mockReturnValue('lightDataPath')
resolveMock.mockImplementation((...v: string[]) => v.join(''))
joinMock.mockImplementation((...v: string[]) => v.join(''))
await CKBLightRunner.getInstance().updateConfig()
expect(CKBLightRunner.getInstance().port).toEqual(9001)
expect(updateTomlMock).toHaveBeenCalledWith('lightDataPath./ckb_light.toml', {
- store: `path = "lightDataPath./store"`,
- network: `path = "lightDataPath./network"`,
- rpc: `listen_address = "127.0.0.1:9001"`,
+ store: {
+ path: `"lightDataPath./store"`,
+ },
+ network: {
+ listen_addresses: '["/ip4/0.0.0.0/tcp/8119"]',
+ path: `"lightDataPath./network"`,
+ },
+ rpc: {
+ listen_address: `"127.0.0.1:9001"`,
+ },
})
//reset port
getUsablePortMock.mockResolvedValueOnce(9000)
await CKBLightRunner.getInstance().updateConfig()
})
it('port is not used', async () => {
- getUsablePortMock.mockResolvedValueOnce(9000)
+ getUsablePortMock.mockResolvedValueOnce(9000).mockResolvedValueOnce(8118)
lightDataPathMock.mockReturnValue('lightDataPath')
resolveMock.mockImplementation((...v: string[]) => v.join(''))
joinMock.mockImplementation((...v: string[]) => v.join(''))
await CKBLightRunner.getInstance().updateConfig()
expect(CKBLightRunner.getInstance().port).toEqual(9000)
expect(updateTomlMock).toHaveBeenCalledWith('lightDataPath./ckb_light.toml', {
- store: `path = "lightDataPath./store"`,
- network: `path = "lightDataPath./network"`,
- rpc: `listen_address = "127.0.0.1:9000"`,
+ store: {
+ path: `"lightDataPath./store"`,
+ },
+ network: {
+ listen_addresses: '["/ip4/0.0.0.0/tcp/8118"]',
+ path: `"lightDataPath./network"`,
+ },
+ rpc: {
+ listen_address: `"127.0.0.1:9000"`,
+ },
})
})
})
diff --git a/packages/neuron-wallet/tests/services/multisig.test.ts b/packages/neuron-wallet/tests/services/multisig.test.ts
index 4f0e72fe7e..444c916b22 100644
--- a/packages/neuron-wallet/tests/services/multisig.test.ts
+++ b/packages/neuron-wallet/tests/services/multisig.test.ts
@@ -9,6 +9,7 @@ import SystemScriptInfo from '../../src/models/system-script-info'
import { computeScriptHash as scriptToHash } from '@ckb-lumos/base/lib/utils'
import { closeConnection, getConnection, initConnection } from '../setupAndTeardown'
import { NetworkType } from '../../src/models/network'
+import { scheduler } from 'timers/promises'
const [alice, bob, charlie] = keyInfos
@@ -30,6 +31,7 @@ jest.mock('../../src/services/networks', () => ({
getCurrent: () => ({
type: NetworkType.Normal,
}),
+ isMainnet: jest.fn(),
}),
}))
@@ -45,6 +47,7 @@ describe('multisig service', () => {
)
const defaultMultisigConfig = MultisigConfig.fromModel(multisigConfigModel)
defaultMultisigConfig.lastestBlockNumber = '0x0'
+ defaultMultisigConfig.startBlockNumber = 0
const lock = {
args: Multisig.hash(
multisigConfigModel.blake160s,
@@ -97,6 +100,7 @@ describe('multisig service', () => {
it('save success', async () => {
const anotherConfig = MultisigConfig.fromModel(multisigConfigModel)
anotherConfig.lastestBlockNumber = '0x0'
+ anotherConfig.startBlockNumber = 0
anotherConfig.r = 2
const res = await multisigService.saveMultisigConfig(anotherConfig)
const count = await getConnection()
@@ -133,6 +137,26 @@ describe('multisig service', () => {
.getOne()
expect(config?.alias).toBe('newalisa')
})
+ it('only update startBlockNumber and original data should not be change', async () => {
+ await multisigService.updateMultisigConfig({
+ id: multisigConfigModel.id!,
+ startBlockNumber: 256,
+ })
+ await scheduler.wait(2_000)
+ const config = await getConnection()
+ .getRepository(MultisigConfig)
+ .createQueryBuilder()
+ .where({
+ id: multisigConfigModel.id,
+ })
+ .getOne()
+ expect(config?.alias).toBe('alias')
+ expect(config?.startBlockNumber).toBe(256)
+ expect(config?.walletId).toBe(multisigConfigModel.walletId)
+ expect(config?.blake160s).toStrictEqual(multisigConfigModel.blake160s)
+ expect(config?.r).toBe(multisigConfigModel.r)
+ expect(config?.m).toBe(multisigConfigModel.m)
+ })
})
describe('test get config', () => {
diff --git a/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts b/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts
index c5217e5f11..c8ba7d414a 100644
--- a/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts
+++ b/packages/neuron-wallet/tests/services/tx/transaction-generator.test.ts
@@ -1,6 +1,6 @@
import { when } from 'jest-when'
-import { since } from '@ckb-lumos/base'
import { bytes } from '@ckb-lumos/codec'
+import { since } from '@ckb-lumos/base'
import OutputEntity from '../../../src/database/chain/entities/output'
import InputEntity from '../../../src/database/chain/entities/input'
import TransactionEntity from '../../../src/database/chain/entities/transaction'
@@ -28,7 +28,7 @@ import {
SudtAcpHaveDataError,
TargetOutputNotFoundError,
} from '../../../src/exceptions'
-import LiveCell from '../../../src/models/chain/live-cell'
+import LiveCell, { CellWithOutPoint } from '../../../src/models/chain/live-cell'
import { keyInfos } from '../../setupAndTeardown/public-key-info.fixture'
const randomHex = (length: number = 64): string => {
@@ -86,7 +86,6 @@ import HdPublicKeyInfo from '../../../src/database/chain/entities/hd-public-key-
import AssetAccount from '../../../src/models/asset-account'
import MultisigConfigModel from '../../../src/models/multisig-config'
import MultisigOutput from '../../../src/database/chain/entities/multisig-output'
-import { LumosCell } from '../../../src/block-sync-renderer/sync/synchronizer'
import { closeConnection, getConnection, initConnection } from '../../setupAndTeardown'
describe('TransactionGenerator', () => {
@@ -1097,8 +1096,8 @@ describe('TransactionGenerator', () => {
tokenID: string | undefined = undefined,
lockScript: Script = bobAnyoneCanPayLockScript,
customData: string = '0x'
- ): LumosCell => {
- const liveCell: LumosCell = {
+ ): CellWithOutPoint => {
+ const liveCell: CellWithOutPoint = {
blockHash: randomHex(),
outPoint: {
txHash: randomHex(),
@@ -1109,18 +1108,17 @@ describe('TransactionGenerator', () => {
lock: {
codeHash: lockScript.codeHash,
args: lockScript.args,
- hashType: lockScript.hashType.toString(),
+ hashType: lockScript.hashType,
},
},
data: '0x',
}
if (tokenID) {
const typeScript = assetAccountInfo.generateSudtScript(tokenID)
- // @ts-ignore
liveCell.cellOutput.type = {
codeHash: typeScript.codeHash,
args: typeScript.args,
- hashType: typeScript.hashType.toString(),
+ hashType: typeScript.hashType,
}
}
liveCell.data = amount ? BufferUtils.writeBigUInt128LE(BigInt(amount)) : '0x'
diff --git a/packages/neuron-wallet/tests/utils/toml/test.toml b/packages/neuron-wallet/tests/utils/toml/test.toml
index 7a693b7094..e5c6426928 100644
--- a/packages/neuron-wallet/tests/utils/toml/test.toml
+++ b/packages/neuron-wallet/tests/utils/toml/test.toml
@@ -17,6 +17,7 @@ log_to_stdout = true
[network]
network = 127
+listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]
### Specify the public and routable network addresses
# public_addresses = []
diff --git a/packages/neuron-wallet/tests/utils/toml/toml.test.ts b/packages/neuron-wallet/tests/utils/toml/toml.test.ts
index 37ea295d0c..1184bcb430 100644
--- a/packages/neuron-wallet/tests/utils/toml/toml.test.ts
+++ b/packages/neuron-wallet/tests/utils/toml/toml.test.ts
@@ -27,41 +27,50 @@ describe('test toml', () => {
resetMock()
})
describe('test update toml', () => {
- it('update skip comment', () => {
+ it('update skip non exist key', () => {
const tomlPath = path.resolve(__dirname, './test.toml')
updateToml(tomlPath, {
- network: 'network = 127',
+ network: {
+ network1: '127',
+ },
})
- expect(writeFileSyncMock).toBeCalledWith(
- tomlPath,
- fs.readFileSync(tomlPath).toString().replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'network = 127')
- )
+ expect(writeFileSyncMock).toBeCalledWith(tomlPath, fs.readFileSync(tomlPath).toString())
})
it('update multi values with new file and dir exist', () => {
const tomlPath = path.resolve(__dirname, './test.toml')
existsSyncMock.mockReturnValue(true)
- updateToml(tomlPath, { network: 'network = 127', rpc: 'rpc = 8116' }, path.resolve(__dirname, './new.toml'))
+ updateToml(
+ tomlPath,
+ { network: { network: '126', listen_addresses: 'test' }, rpc: { listen_address: 'listen_address' } },
+ path.resolve(__dirname, './new.toml')
+ )
expect(writeFileSyncMock).toBeCalledWith(
path.resolve(__dirname, './new.toml'),
fs
.readFileSync(tomlPath)
.toString()
- .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'network = 127')
- .replace('listen_address = "127.0.0.1:8114"', 'rpc = 8116')
+ .replace('network = 127', 'network = 126')
+ .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'listen_addresses = test')
+ .replace('listen_address = "127.0.0.1:8114"', 'listen_address = listen_address')
)
})
it('update multi values with new file and dir not exist', () => {
const tomlPath = path.resolve(__dirname, './test.toml')
existsSyncMock.mockReturnValue(false)
- updateToml(tomlPath, { network: 'network = 127', rpc: 'rpc = 8116' }, path.resolve(__dirname, './new.toml'))
+ updateToml(
+ tomlPath,
+ { network: { network: '126', listen_addresses: 'test' }, rpc: { listen_address: 'listen_address' } },
+ path.resolve(__dirname, './new.toml')
+ )
expect(mkdirSyncMock).toBeCalledWith(__dirname, { recursive: true })
expect(writeFileSyncMock).toBeCalledWith(
path.resolve(__dirname, './new.toml'),
fs
.readFileSync(tomlPath)
.toString()
- .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'network = 127')
- .replace('listen_address = "127.0.0.1:8114"', 'rpc = 8116')
+ .replace('network = 127', 'network = 126')
+ .replace('listen_addresses = ["/ip4/0.0.0.0/tcp/8115"]', 'listen_addresses = test')
+ .replace('listen_address = "127.0.0.1:8114"', 'listen_address = listen_address')
)
})
})
| |