diff --git a/packages/neuron-wallet/src/exceptions/multisig.ts b/packages/neuron-wallet/src/exceptions/multisig.ts index 5eef3e0dfd..5afb135b1c 100644 --- a/packages/neuron-wallet/src/exceptions/multisig.ts +++ b/packages/neuron-wallet/src/exceptions/multisig.ts @@ -25,6 +25,7 @@ export class MultisigConfigAddressError extends Error { } export class MultisigConfigNeedError extends Error { + public code = 502 constructor() { super(t('messages.multisig-config-need-error')) } diff --git a/packages/neuron-wallet/src/locales/ar.ts b/packages/neuron-wallet/src/locales/ar.ts index f72a67161d..2f00419a5c 100644 --- a/packages/neuron-wallet/src/locales/ar.ts +++ b/packages/neuron-wallet/src/locales/ar.ts @@ -221,6 +221,13 @@ export default { cancel: 'إلغاء', }, }, + 'unrecognized-lock-script': { + message: 'تم العثور على نص قفل غير معرّف في هذه المعاملة، يرجى التحقق.', + buttons: { + cancel: 'إلغاء', + ignore: 'تجاهل واستمرار', + }, + }, }, prompt: { password: { diff --git a/packages/neuron-wallet/src/locales/en.ts b/packages/neuron-wallet/src/locales/en.ts index fec1bc382c..82e3b7d27c 100644 --- a/packages/neuron-wallet/src/locales/en.ts +++ b/packages/neuron-wallet/src/locales/en.ts @@ -223,6 +223,13 @@ export default { cancel: 'Cancel', }, }, + 'unrecognized-lock-script': { + message: 'An unrecognized lock script was found in this transaction, please check it.', + buttons: { + cancel: 'Cancel', + ignore: 'Ignore and continue', + }, + }, }, prompt: { password: { diff --git a/packages/neuron-wallet/src/locales/es.ts b/packages/neuron-wallet/src/locales/es.ts index 9d70452efd..6c6855becd 100644 --- a/packages/neuron-wallet/src/locales/es.ts +++ b/packages/neuron-wallet/src/locales/es.ts @@ -226,6 +226,13 @@ export default { cancel: 'Cancelar', }, }, + 'unrecognized-lock-script': { + message: 'Se encontró un script de bloqueo no reconocido en esta transacción, por favor verifíquelo.', + buttons: { + cancel: 'Cancelar', + ignore: 'Ignorar y continuar', + }, + }, }, prompt: { password: { diff --git a/packages/neuron-wallet/src/locales/fr.ts b/packages/neuron-wallet/src/locales/fr.ts index 58e11e3d3a..c87442f556 100644 --- a/packages/neuron-wallet/src/locales/fr.ts +++ b/packages/neuron-wallet/src/locales/fr.ts @@ -227,6 +227,13 @@ export default { cancel: 'Annuler', }, }, + 'unrecognized-lock-script': { + message: 'Un script de verrouillage non reconnu a été trouvé dans cette transaction, veuillez vérifier.', + buttons: { + cancel: 'Annuler', + ignore: 'Ignorer et continuer', + }, + }, }, prompt: { password: { diff --git a/packages/neuron-wallet/src/locales/zh-tw.ts b/packages/neuron-wallet/src/locales/zh-tw.ts index cc75c175f4..7567c2f8d3 100644 --- a/packages/neuron-wallet/src/locales/zh-tw.ts +++ b/packages/neuron-wallet/src/locales/zh-tw.ts @@ -209,6 +209,13 @@ export default { cancel: '取消', }, }, + 'unrecognized-lock-script': { + message: '在此交易中發現了一個未識別的lock script,請檢查。', + buttons: { + cancel: '取消', + ignore: '忽略並繼續', + }, + }, }, prompt: { password: { diff --git a/packages/neuron-wallet/src/locales/zh.ts b/packages/neuron-wallet/src/locales/zh.ts index 5200e52497..52b09f1210 100644 --- a/packages/neuron-wallet/src/locales/zh.ts +++ b/packages/neuron-wallet/src/locales/zh.ts @@ -210,6 +210,13 @@ export default { cancel: '取消', }, }, + 'unrecognized-lock-script': { + message: '在此交易中发现了一个未识别的lock script,请检查。', + buttons: { + cancel: '取消', + ignore: '忽略并继续', + }, + }, }, prompt: { password: { diff --git a/packages/neuron-wallet/src/services/transaction-sender.ts b/packages/neuron-wallet/src/services/transaction-sender.ts index ebe753e0c1..df98b06acc 100644 --- a/packages/neuron-wallet/src/services/transaction-sender.ts +++ b/packages/neuron-wallet/src/services/transaction-sender.ts @@ -1,3 +1,5 @@ +import { t } from 'i18next' +import { dialog } from 'electron' import { serializeWitnessArgs } from '../utils/serialization' import { scriptToAddress } from '../utils/scriptAndAddress' import { TargetOutput, TransactionGenerator, TransactionPersistor } from './tx' @@ -198,7 +200,27 @@ export default class TransactionSender { // A 65-byte empty signature used as placeholder witnessesArgs[0].witnessArgs.setEmptyLock() - const privateKey = findPrivateKey(witnessesArgs[0].lockArgs) + let privateKey = '' + try { + privateKey = findPrivateKey(witnessesArgs[0].lockArgs) + } catch (error) { + const BLOCK_UNRECOGNIZED = 0 + const IGNORE_UNRECOGNIZED_AND_CONTINUE = 1 + const res = await dialog.showMessageBox({ + type: 'warning', + message: t('messageBox.unrecognized-lock-script.message'), + buttons: [ + t('messageBox.unrecognized-lock-script.buttons.cancel'), + t('messageBox.unrecognized-lock-script.buttons.ignore'), + ], + defaultId: BLOCK_UNRECOGNIZED, + cancelId: IGNORE_UNRECOGNIZED_AND_CONTINUE, + }) + if (res.response === IGNORE_UNRECOGNIZED_AND_CONTINUE) { + continue + } + throw error + } const serializedWitnesses: (WitnessArgs | string)[] = witnessesArgs.map((value: SignInfo, index: number) => { const args = value.witnessArgs @@ -330,6 +352,21 @@ export default class TransactionSender { for (const lockHash of lockHashes) { const multisigConfig = multisigConfigMap[lockHash] if (!multisigConfig) { + const BLOCK_UNRECOGNIZED = 0 + const IGNORE_UNRECOGNIZED_AND_CONTINUE = 1 + const res = await dialog.showMessageBox({ + type: 'warning', + message: t('messageBox.unrecognized-lock-script.message'), + buttons: [ + t('messageBox.unrecognized-lock-script.buttons.cancel'), + t('messageBox.unrecognized-lock-script.buttons.ignore'), + ], + defaultId: BLOCK_UNRECOGNIZED, + cancelId: IGNORE_UNRECOGNIZED_AND_CONTINUE, + }) + if (res.response === IGNORE_UNRECOGNIZED_AND_CONTINUE) { + continue + } throw new MultisigConfigNeedError() } const [privateKey, blake160] = findPrivateKeyAndBlake160(multisigConfig.blake160s, tx.signatures?.[lockHash]) diff --git a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts index eaf1894650..b73ae330ed 100644 --- a/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts +++ b/packages/neuron-wallet/tests/services/tx/transaction-sender.test.ts @@ -1,3 +1,4 @@ +import { dialog } from 'electron' import { CKBComponents } from '@ckb-lumos/lumos/rpc' import { bytes } from '@ckb-lumos/lumos/codec' import 'dotenv/config' @@ -181,6 +182,12 @@ jest.doMock('services/cells', () => ({ getLiveCell: stubbedGetLiveCell, })) +jest.mock('electron', () => ({ + dialog: { + showMessageBox: jest.fn(), + }, +})) + import Transaction from '../../../src/models/chain/transaction' import TxStatus from '../../../src/models/chain/tx-status' import CellDep, { DepType } from '../../../src/models/chain/cell-dep' @@ -1001,13 +1008,28 @@ describe('TransactionSender Test', () => { }) }) - it('throw exception no matched multisig config', async () => { + it('no matched multisig config, ignore and continue', async () => { + const showMessageBoxMock = jest + .spyOn(dialog, 'showMessageBox') + .mockImplementation(() => Promise.resolve({ response: 1, checkboxChecked: true })) + mockGAI.mockReturnValueOnce([{ path: '' }]) + transactionSender.getAddressInfos = mockGAI.bind(transactionSender) + const tx = Transaction.fromObject(transactionObject) + await expect(transactionSender.signMultisig(fakeWallet.id, tx, '1234', [])).resolves.not.toThrow() + expect(showMessageBoxMock).toHaveBeenCalled() + }) + + it('no matched multisig config, throw exception', async () => { + const showMessageBoxMock = jest + .spyOn(dialog, 'showMessageBox') + .mockImplementation(() => Promise.resolve({ response: 0, checkboxChecked: false })) mockGAI.mockReturnValueOnce([{ path: '' }]) transactionSender.getAddressInfos = mockGAI.bind(transactionSender) const tx = Transaction.fromObject(transactionObject) await expect(transactionSender.signMultisig(fakeWallet.id, tx, '1234', [])).rejects.toThrowError( new MultisigConfigNeedError() ) + expect(showMessageBoxMock).toHaveBeenCalled() }) it('throw exception no matched multisig config addresses', async () => {