Skip to content

Commit 6e70c94

Browse files
committed
fix: Manage Nervos DAO with multisig address
1 parent 0d4c967 commit 6e70c94

File tree

10 files changed

+97
-32
lines changed

10 files changed

+97
-32
lines changed

packages/neuron-ui/src/components/MultisigAddress/index.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,25 @@ const MultisigAddress = () => {
204204
[listActionOptions]
205205
)
206206

207+
const daoDisabledMessage = useMemo(() => {
208+
if (wallet.device) {
209+
if (
210+
(daoDepositAction.depositFromMultisig && daoDepositAction.isDialogOpen) ||
211+
(daoWithdrawAction.withdrawFromMultisig && daoWithdrawAction.isDialogOpen)
212+
) {
213+
const multisigConfig = daoDepositAction.depositFromMultisig || daoWithdrawAction.withdrawFromMultisig
214+
if (!multisigConfig) return ''
215+
const { canSign } = getMultisigSignStatus({
216+
multisigConfig,
217+
addresses,
218+
})
219+
220+
return canSign ? 'dao-ledger-notice' : 'dao-hardware-not-match'
221+
}
222+
}
223+
return ''
224+
}, [daoDepositAction, daoWithdrawAction, wallet.device, addresses])
225+
207226
const { keywords, onChange, onBlur } = useSearch(clearSelected, onFilterConfig)
208227

209228
const sendTotalBalance = useMemo(() => {
@@ -584,7 +603,7 @@ const MultisigAddress = () => {
584603
/>
585604
) : null}
586605

587-
{daoDepositAction.depositFromMultisig && daoDepositAction.isDialogOpen ? (
606+
{!daoDisabledMessage && daoDepositAction.depositFromMultisig && daoDepositAction.isDialogOpen ? (
588607
<DepositDialog
589608
balance={multisigBanlances[daoDepositAction.depositFromMultisig.fullPayload]}
590609
wallet={wallet}
@@ -600,12 +619,23 @@ const MultisigAddress = () => {
600619
/>
601620
) : null}
602621

603-
{daoWithdrawAction.withdrawFromMultisig && daoWithdrawAction.isDialogOpen ? (
622+
{!daoDisabledMessage && daoWithdrawAction.withdrawFromMultisig && daoWithdrawAction.isDialogOpen ? (
604623
<MultisigAddressNervosDAODialog
605624
closeDialog={daoWithdrawAction.closeDialog}
606625
multisigConfig={daoWithdrawAction.withdrawFromMultisig}
607626
/>
608627
) : null}
628+
629+
<AlertDialog
630+
show={!!daoDisabledMessage}
631+
message={t(`multisig-address.${daoDisabledMessage}`)}
632+
type="warning"
633+
okProps={{ style: { display: 'none' } }}
634+
onCancel={() => {
635+
daoDepositAction.closeDialog()
636+
daoWithdrawAction.closeDialog()
637+
}}
638+
/>
609639
</div>
610640
)
611641
}

packages/neuron-ui/src/locales/ar.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,8 @@
11711171
"daoWithdraw": "سحب من DAO"
11721172
}
11731173
},
1174+
"dao-ledger-notice": "تدعم محافظ Ledger حاليًا توقيع معاملات DAO فقط، ولا تدعم بدء الإيداعات أو السحوبات. يرجى التحقق من التحديثات المستقبلية.",
1175+
"dao-hardware-not-match": "المحفظة الصلبة المتصلة حاليًا لا تتطابق مع المحفظة الحالية.",
11741176
"import-dialog": {
11751177
"actions": {
11761178
"cancel": "إلغاء",

packages/neuron-ui/src/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,8 @@
11711171
"daoWithdraw": "DAO Withdraw"
11721172
}
11731173
},
1174+
"dao-ledger-notice": "Ledger wallets currently support only signing DAO transactions, not initiating deposits or withdrawals. Please check back for future updates.",
1175+
"dao-hardware-not-match": "The hardware wallet currently connected does not match the current wallet.",
11741176
"import-dialog": {
11751177
"actions": {
11761178
"cancel": "Cancel",

packages/neuron-ui/src/locales/es.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,8 @@
11541154
"daoWithdraw": "Retirar de DAO"
11551155
}
11561156
},
1157+
"dao-ledger-notice": "Las billeteras Ledger actualmente solo admiten la firma de transacciones DAO, no la iniciación de depósitos o retiros. Vuelva a consultar para futuras actualizaciones.",
1158+
"dao-hardware-not-match": "La billetera de hardware conectada actualmente no coincide con la billetera actual.",
11571159
"import-dialog": {
11581160
"actions": {
11591161
"cancel": "Cancelar",

packages/neuron-ui/src/locales/fr.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,8 @@
11611161
"daoWithdraw": "Retirer de DAO"
11621162
}
11631163
},
1164+
"dao-ledger-notice": "Les portefeuilles Ledger prennent actuellement en charge uniquement la signature des transactions DAO, mais pas l’initiation des dépôts ou des retraits. Veuillez vérifier les mises à jour futures.",
1165+
"dao-hardware-not-match": "Le portefeuille matériel actuellement connecté ne correspond pas au portefeuille actuel.",
11641166
"import-dialog": {
11651167
"actions": {
11661168
"cancel": "Annuler",

packages/neuron-ui/src/locales/zh-tw.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,8 @@
11641164
"daoWithdraw": "從 DAO 取出"
11651165
}
11661166
},
1167+
"dao-ledger-notice": "Ledger 錢包目前僅支援簽署 DAO 交易,無法發起存款或提取。請關注未來的更新。",
1168+
"dao-hardware-not-match": "當前連接的硬體錢包與當前錢包不匹配。",
11671169
"import-dialog": {
11681170
"actions": {
11691171
"cancel": "取消",

packages/neuron-ui/src/locales/zh.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,8 @@
11631163
"daoWithdraw": "从 DAO 取出"
11641164
}
11651165
},
1166+
"dao-ledger-notice": "Ledger 钱包目前仅支持签署 DAO 交易,无法发起存款或提取。请关注未来的更新。",
1167+
"dao-hardware-not-match": "当前连接的硬件钱包与当前钱包不匹配。",
11661168
"import-dialog": {
11671169
"actions": {
11681170
"cancel": "取消",

packages/neuron-wallet/src/services/cells.ts

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,15 +1321,6 @@ export default class CellsService {
13211321
return {}
13221322
}
13231323
const lockHashes = multisigAddresses.map(v => scriptToHash(addressToScript(v)))
1324-
1325-
const outputs = await getConnection()
1326-
.getRepository(OutputEntity)
1327-
.createQueryBuilder('output')
1328-
.where('output.lockHash IN (:...lockHashes)', { lockHashes })
1329-
.andWhere('output.hasData = :hasData', { hasData: true })
1330-
.andWhere('output.typeHash IS NOT NULL')
1331-
.getMany()
1332-
13331324
const connection = await getConnection()
13341325
const [sql, parameters] = connection.driver.escapeQueryWithParameters(
13351326
`
@@ -1345,7 +1336,7 @@ export default class CellsService {
13451336
`,
13461337
{
13471338
lockHashes,
1348-
statuses: [OutputStatus.Live, OutputStatus.Sent],
1339+
statuses: [OutputStatus.Live],
13491340
},
13501341
{}
13511342
)
@@ -1369,18 +1360,6 @@ export default class CellsService {
13691360
] = c.balance
13701361
})
13711362

1372-
outputs.forEach(item => {
1373-
const key = scriptToAddress(
1374-
{
1375-
args: item.lockArgs,
1376-
codeHash: SystemScriptInfo.MULTI_SIGN_CODE_HASH,
1377-
hashType: SystemScriptInfo.MULTI_SIGN_HASH_TYPE,
1378-
},
1379-
isMainnet
1380-
)
1381-
balances[key] = (BigInt(balances[key]) - BigInt(item.capacity)).toString()
1382-
})
1383-
13841363
return balances
13851364
}
13861365

packages/neuron-wallet/src/services/multisig.ts

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import Multisig from '../models/multisig'
1313
import SyncProgress, { SyncAddressType } from '../database/chain/entities/sync-progress'
1414
import { NetworkType } from '../models/network'
1515
import logger from '../utils/logger'
16+
import { TransactionPersistor } from './tx'
17+
import { DAO_DATA } from '../utils/const'
18+
import RpcService from '../services/rpc-service'
19+
import TransactionWithStatus from '../models/chain/transaction-with-status'
20+
import TxStatus from '../models/chain/tx-status'
21+
import SystemScriptInfo from '../models/system-script-info'
1622

1723
const max64Int = '0x' + 'f'.repeat(16)
1824
export default class MultisigService {
@@ -107,8 +113,8 @@ export default class MultisigService {
107113
})
108114
}
109115

110-
static async getLiveCells(multisigConfigs: MultisigConfig[]) {
111-
const liveCells: MultisigOutput[] = []
116+
static async getCells(multisigConfigs: MultisigConfig[]) {
117+
const cells: any[] = []
112118
const addressCursorMap: Map<string, string> = new Map()
113119
let currentMultisigConfigs = MultisigService.removeDulpicateConfig(multisigConfigs)
114120
const network = NetworksService.getInstance().getCurrent()
@@ -144,17 +150,18 @@ export default class MultisigService {
144150
const config = currentMultisigConfigs[idx]
145151
const script = Multisig.getMultisigScript(config.blake160s, config.r, config.m, config.n)
146152
addressCursorMap.set(script.args, v?.result?.last_cursor)
147-
liveCells.push(
148-
...v.result.objects
149-
.filter((object: any) => !object?.output?.type)
150-
.map((object: any) => MultisigOutput.fromIndexer(object))
151-
)
153+
cells.push(...v.result.objects)
152154
nextMultisigConfigs.push(currentMultisigConfigs[idx])
153155
}
154156
})
155157
currentMultisigConfigs = nextMultisigConfigs
156158
}
157-
return liveCells
159+
return cells
160+
}
161+
162+
static async getLiveCells(multisigConfigs: MultisigConfig[]) {
163+
const cells = await MultisigService.getCells(multisigConfigs)
164+
return cells.filter((object: any) => !object?.output?.type).map((object: any) => MultisigOutput.fromIndexer(object))
158165
}
159166

160167
static async saveLiveMultisigOutput() {
@@ -166,6 +173,41 @@ export default class MultisigService {
166173
}
167174
}
168175

176+
static async saveMultisigDaoTx(multisigConfigs: MultisigConfig[]) {
177+
const cells = await MultisigService.getCells(multisigConfigs)
178+
if (cells.length) {
179+
const daoTxHash = new Set<string>()
180+
cells.forEach((cell: any) => {
181+
if (cell?.output?.type?.code_hash === SystemScriptInfo.DAO_CODE_HASH) {
182+
daoTxHash.add(cell.out_point.tx_hash)
183+
}
184+
})
185+
if (daoTxHash.size > 0) {
186+
const network = NetworksService.getInstance().getCurrent()
187+
const rpcService = new RpcService(network.remote, network.type)
188+
for (const txHash of daoTxHash) {
189+
const txWithStatus: TransactionWithStatus | undefined | { transaction: null; txStatus: TxStatus } =
190+
await rpcService.getTransaction(txHash)
191+
if (txWithStatus?.transaction) {
192+
const tx = Transaction.fromSDK(txWithStatus.transaction)
193+
tx.blockHash = txWithStatus.txStatus.blockHash || undefined
194+
if (tx.blockHash) {
195+
const header = await rpcService.getHeader(tx.blockHash)
196+
tx.timestamp = header?.timestamp
197+
tx.blockNumber = header?.number
198+
}
199+
tx.outputsData.forEach((item, index) => {
200+
if (item === DAO_DATA) {
201+
tx.outputs[index].daoData = DAO_DATA
202+
}
203+
})
204+
await TransactionPersistor.saveFetchTx(tx)
205+
}
206+
}
207+
}
208+
}
209+
}
210+
169211
static async getMultisigTransactionHashList(multisigConfigs: MultisigConfig[]) {
170212
const multisigOutputTxHashList = new Set<string>()
171213
const addressCursorMap: Map<string, string> = new Map()
@@ -302,6 +344,7 @@ export default class MultisigService {
302344
try {
303345
const multisigConfigs = await getConnection().getRepository(MultisigConfig).createQueryBuilder().getMany()
304346
await MultisigService.saveLiveMultisigOutput()
347+
await MultisigService.saveMultisigDaoTx(multisigConfigs)
305348
await MultisigService.deleteDeadMultisigOutput(multisigConfigs)
306349
await MultisigService.saveMultisigSyncBlockNumber(multisigConfigs, lastestBlockNumber)
307350
MultisigOutputChangedSubject.getSubject().next('update')

packages/neuron-wallet/src/utils/const.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const DEFAULT_ARGS_LENGTH = 42
1919
export const LOCKTIME_ARGS_LENGTH = 58
2020
export const CHEQUE_ARGS_LENGTH = 82
2121
export const CKB_NODE_DATA_SIZE_BUFFER_RATIO = 1.2
22+
export const DAO_DATA = '0x0000000000000000'
2223

2324
export enum ResponseCode {
2425
Fail,

0 commit comments

Comments
 (0)