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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions packages/neuron-ui/src/components/MultisigAddress/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,25 @@ const MultisigAddress = () => {
[listActionOptions]
)

const daoDisabledMessage = useMemo(() => {
if (!wallet.device) return ''

if (
(daoDepositAction.depositFromMultisig && daoDepositAction.isDialogOpen) ||
(daoWithdrawAction.withdrawFromMultisig && daoWithdrawAction.isDialogOpen)
) {
const multisigConfig = daoDepositAction.depositFromMultisig || daoWithdrawAction.withdrawFromMultisig
const { canSign } = getMultisigSignStatus({
multisigConfig: multisigConfig!,
addresses,
})

return canSign ? 'dao-ledger-notice' : 'dao-hardware-not-match'
}

return ''
}, [daoDepositAction, daoWithdrawAction, wallet.device, addresses])

const { keywords, onChange, onBlur } = useSearch(clearSelected, onFilterConfig)

const sendTotalBalance = useMemo(() => {
Expand Down Expand Up @@ -584,7 +603,7 @@ const MultisigAddress = () => {
/>
) : null}

{daoDepositAction.depositFromMultisig && daoDepositAction.isDialogOpen ? (
{!daoDisabledMessage && daoDepositAction.depositFromMultisig && daoDepositAction.isDialogOpen ? (
<DepositDialog
balance={multisigBanlances[daoDepositAction.depositFromMultisig.fullPayload]}
wallet={wallet}
Expand All @@ -600,12 +619,23 @@ const MultisigAddress = () => {
/>
) : null}

{daoWithdrawAction.withdrawFromMultisig && daoWithdrawAction.isDialogOpen ? (
{!daoDisabledMessage && daoWithdrawAction.withdrawFromMultisig && daoWithdrawAction.isDialogOpen ? (
<MultisigAddressNervosDAODialog
closeDialog={daoWithdrawAction.closeDialog}
multisigConfig={daoWithdrawAction.withdrawFromMultisig}
/>
) : null}

<AlertDialog
show={!!daoDisabledMessage}
message={t(`multisig-address.${daoDisabledMessage}`)}
type="warning"
okProps={{ style: { display: 'none' } }}
onCancel={() => {
daoDepositAction.closeDialog()
daoWithdrawAction.closeDialog()
}}
/>
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/neuron-ui/src/components/WithdrawDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const WithdrawDialog = ({
(Number(currentEpochInfo.number) + Number(currentEpochInfo.index) / Number(currentEpochInfo.length))
).toFixed(1)
const message =
epochs >= 0 ? (
epochs > 5 ? (
<>
<Attention />
{t('nervos-dao.notice-wait-time', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
margin: 44px 0 0 0;
border: 1px solid rgba(252, 136, 0, 0.2);
padding: 8px 36px;
width: max-content;
max-width: 760px;
border-radius: 4px;
background: #fff6eb;
color: #f68c2a;
Expand Down
2 changes: 2 additions & 0 deletions packages/neuron-ui/src/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,8 @@
"daoWithdraw": "سحب من DAO"
}
},
"dao-ledger-notice": "محافظ Ledger لا تدعم حاليًا معاملات DAO لعناوين التوقيع المتعدد. يُرجى استخدام عنوان بتوقيع فردي أو الانتظار للتحديثات المستقبلية.",
"dao-hardware-not-match": "المحفظة الصلبة المتصلة حاليًا لا تتطابق مع المحفظة الحالية.",
"import-dialog": {
"actions": {
"cancel": "إلغاء",
Expand Down
2 changes: 2 additions & 0 deletions packages/neuron-ui/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,8 @@
"daoWithdraw": "DAO Withdraw"
}
},
"dao-ledger-notice": "Ledger wallets currently do not support DAO transactions for multisig addresses. Please use a single-signature address or await future updates.",
"dao-hardware-not-match": "The hardware wallet currently connected does not match the current wallet.",
"import-dialog": {
"actions": {
"cancel": "Cancel",
Expand Down
2 changes: 2 additions & 0 deletions packages/neuron-ui/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,8 @@
"daoWithdraw": "Retirar de DAO"
}
},
"dao-ledger-notice": "Las billeteras Ledger actualmente no admiten transacciones DAO para direcciones multifirma. Por favor, use una dirección de firma única o espere futuras actualizaciones.",
"dao-hardware-not-match": "La billetera de hardware conectada actualmente no coincide con la billetera actual.",
"import-dialog": {
"actions": {
"cancel": "Cancelar",
Expand Down
2 changes: 2 additions & 0 deletions packages/neuron-ui/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,8 @@
"daoWithdraw": "Retirer de DAO"
}
},
"dao-ledger-notice": "Les portefeuilles Ledger ne prennent actuellement pas en charge les transactions DAO pour les adresses multisignatures. Veuillez utiliser une adresse à signature unique ou attendre les futures mises à jour.",
"dao-hardware-not-match": "Le portefeuille matériel actuellement connecté ne correspond pas au portefeuille actuel.",
"import-dialog": {
"actions": {
"cancel": "Annuler",
Expand Down
2 changes: 2 additions & 0 deletions packages/neuron-ui/src/locales/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,8 @@
"daoWithdraw": "從 DAO 取出"
}
},
"dao-ledger-notice": "Ledger 錢包目前不支援多重簽名地址的 DAO 交易。請使用單一簽名地址或等待未來的更新。",
"dao-hardware-not-match": "當前連接的硬體錢包與當前錢包不匹配。",
"import-dialog": {
"actions": {
"cancel": "取消",
Expand Down
2 changes: 2 additions & 0 deletions packages/neuron-ui/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,8 @@
"daoWithdraw": "从 DAO 取出"
}
},
"dao-ledger-notice": "Ledger 钱包目前不支持多签地址的 DAO 交易。请使用单签地址或等待未来的更新。",
"dao-hardware-not-match": "当前连接的硬件钱包与当前钱包不匹配。",
"import-dialog": {
"actions": {
"cancel": "取消",
Expand Down
10 changes: 5 additions & 5 deletions packages/neuron-ui/src/styles/mixin.scss
Original file line number Diff line number Diff line change
Expand Up @@ -196,23 +196,23 @@
height: 20px;
padding-left: 30px;
line-height: 20px;
background: url('../widgets/Icons/Checkbox.svg') no-repeat left top;
background: url('widgets/Icons/Checkbox.svg') no-repeat left top;
user-select: none;
}
input[type='checkbox']:checked + span {
background: url('../widgets/Icons/CheckboxSelected.svg') no-repeat left top;
background: url('widgets/Icons/CheckboxSelected.svg') no-repeat left top;
}

input[type='checkbox']:disabled:checked + span {
background: url('../widgets/Icons/CheckboxSelected.svg') no-repeat left top;
background: url('widgets/Icons/CheckboxSelected.svg') no-repeat left top;
opacity: 0.5;
}
input[type='checkbox']:disabled + span {
cursor: not-allowed;
background: url('../widgets/Icons/CheckboxDisabled.svg') no-repeat left top;
background: url('widgets/Icons/CheckboxDisabled.svg') no-repeat left top;

@media (prefers-color-scheme: dark) {
background: url('../widgets/Icons/CheckboxDisabledDark.svg') no-repeat left top;
background: url('widgets/Icons/CheckboxDisabledDark.svg') no-repeat left top;
}
}
}
Expand Down
23 changes: 1 addition & 22 deletions packages/neuron-wallet/src/services/cells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1321,15 +1321,6 @@ export default class CellsService {
return {}
}
const lockHashes = multisigAddresses.map(v => scriptToHash(addressToScript(v)))

const outputs = await getConnection()
.getRepository(OutputEntity)
.createQueryBuilder('output')
.where('output.lockHash IN (:...lockHashes)', { lockHashes })
.andWhere('output.hasData = :hasData', { hasData: true })
.andWhere('output.typeHash IS NOT NULL')
.getMany()

const connection = await getConnection()
const [sql, parameters] = connection.driver.escapeQueryWithParameters(
`
Expand All @@ -1345,7 +1336,7 @@ export default class CellsService {
`,
{
lockHashes,
statuses: [OutputStatus.Live, OutputStatus.Sent],
statuses: [OutputStatus.Live],
},
{}
)
Expand All @@ -1369,18 +1360,6 @@ export default class CellsService {
] = c.balance
})

outputs.forEach(item => {
const key = scriptToAddress(
{
args: item.lockArgs,
codeHash: SystemScriptInfo.MULTI_SIGN_CODE_HASH,
hashType: SystemScriptInfo.MULTI_SIGN_HASH_TYPE,
},
isMainnet
)
balances[key] = (BigInt(balances[key]) - BigInt(item.capacity)).toString()
})

return balances
}

Expand Down
79 changes: 71 additions & 8 deletions packages/neuron-wallet/src/services/multisig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import Multisig from '../models/multisig'
import SyncProgress, { SyncAddressType } from '../database/chain/entities/sync-progress'
import { NetworkType } from '../models/network'
import logger from '../utils/logger'
import { TransactionPersistor } from './tx'
import { DAO_DATA } from '../utils/const'
import RpcService from '../services/rpc-service'
import TransactionWithStatus from '../models/chain/transaction-with-status'
import TxStatus from '../models/chain/tx-status'
import SystemScriptInfo from '../models/system-script-info'
import OutPoint from '../models/chain/out-point'

const max64Int = '0x' + 'f'.repeat(16)
export default class MultisigService {
Expand Down Expand Up @@ -107,8 +114,8 @@ export default class MultisigService {
})
}

static async getLiveCells(multisigConfigs: MultisigConfig[]) {
const liveCells: MultisigOutput[] = []
static async getCells(multisigConfigs: MultisigConfig[]) {
const cells: RPC.IndexerCell[] = []
const addressCursorMap: Map<string, string> = new Map()
let currentMultisigConfigs = MultisigService.removeDulpicateConfig(multisigConfigs)
const network = NetworksService.getInstance().getCurrent()
Expand Down Expand Up @@ -144,17 +151,18 @@ export default class MultisigService {
const config = currentMultisigConfigs[idx]
const script = Multisig.getMultisigScript(config.blake160s, config.r, config.m, config.n)
addressCursorMap.set(script.args, v?.result?.last_cursor)
liveCells.push(
...v.result.objects
.filter((object: any) => !object?.output?.type)
.map((object: any) => MultisigOutput.fromIndexer(object))
)
cells.push(...v.result.objects)
nextMultisigConfigs.push(currentMultisigConfigs[idx])
}
})
currentMultisigConfigs = nextMultisigConfigs
}
return liveCells
return cells
}

static async getLiveCells(multisigConfigs: MultisigConfig[]) {
const cells = await MultisigService.getCells(multisigConfigs)
return cells.filter(object => !object?.output?.type).map(object => MultisigOutput.fromIndexer(object))
}

static async saveLiveMultisigOutput() {
Expand All @@ -166,6 +174,60 @@ export default class MultisigService {
}
}

static async saveMultisigDaoTx(multisigConfigs: MultisigConfig[]) {
const cells = await MultisigService.getCells(multisigConfigs)
if (cells.length) {
const daoTxHash = new Set<string>()
cells.forEach(cell => {
if (cell.output?.type?.code_hash === SystemScriptInfo.DAO_CODE_HASH) {
daoTxHash.add(cell.out_point.tx_hash)
}
})

const network = NetworksService.getInstance().getCurrent()
const rpcService = new RpcService(network.remote, network.type)

const getTx = async (txHash: string) => {
const txWithStatus: TransactionWithStatus | undefined | { transaction: null; txStatus: TxStatus } =
await rpcService.getTransaction(txHash)
if (txWithStatus?.transaction) {
const tx = Transaction.fromSDK(txWithStatus.transaction)
tx.blockHash = txWithStatus.txStatus.blockHash || undefined
if (tx.blockHash) {
const header = await rpcService.getHeader(tx.blockHash)
tx.timestamp = header?.timestamp
tx.blockNumber = header?.number
}
return tx
}
}

if (daoTxHash.size > 0) {
for (const txHash of daoTxHash) {
const tx = await getTx(txHash)
if (tx) {
const previousTxHashes: string[] = []
tx.outputs.forEach((output, index) => {
if (output.type?.codeHash === SystemScriptInfo.DAO_CODE_HASH) {
output.daoData = tx.outputsData[index]
if (tx.outputsData[index] !== DAO_DATA) {
const previousTxHash = tx.inputs[index].previousOutput!.txHash
previousTxHashes.push(previousTxHash)
output.setDepositOutPoint(new OutPoint(previousTxHash, tx.inputs[index].previousOutput!.index))
}
}
})
for (const previousTxHash of previousTxHashes) {
const previousTx = await getTx(previousTxHash)
if (previousTx) await TransactionPersistor.saveFetchTx(previousTx)
}
await TransactionPersistor.saveFetchTx(tx)
}
}
}
}
}

static async getMultisigTransactionHashList(multisigConfigs: MultisigConfig[]) {
const multisigOutputTxHashList = new Set<string>()
const addressCursorMap: Map<string, string> = new Map()
Expand Down Expand Up @@ -302,6 +364,7 @@ export default class MultisigService {
try {
const multisigConfigs = await getConnection().getRepository(MultisigConfig).createQueryBuilder().getMany()
await MultisigService.saveLiveMultisigOutput()
await MultisigService.saveMultisigDaoTx(multisigConfigs)
await MultisigService.deleteDeadMultisigOutput(multisigConfigs)
await MultisigService.saveMultisigSyncBlockNumber(multisigConfigs, lastestBlockNumber)
MultisigOutputChangedSubject.getSubject().next('update')
Expand Down
8 changes: 5 additions & 3 deletions packages/neuron-wallet/src/services/transaction-sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -896,8 +896,7 @@ export default class TransactionSender {
multisigConfig.m,
multisigConfig.n
)
const multisigAddresses = scriptToAddress(lockScript, NetworksService.getInstance().isMainnet())
output = new Output(outputCapacity.toString(), AddressParser.parse(multisigAddresses), undefined, '0x')
output = new Output(outputCapacity.toString(), lockScript, undefined, '0x')
} else {
const wallet = WalletService.getInstance().get(walletID)
const address = await wallet.getNextAddress()
Expand All @@ -919,7 +918,10 @@ export default class TransactionSender {
withdrawOutput.lock
)

const withdrawWitnessArgs: WitnessArgs = new WitnessArgs(WitnessArgs.EMPTY_LOCK, '0x0000000000000000')
const withdrawWitnessArgs: WitnessArgs = new WitnessArgs(
multisigConfig ? '' : WitnessArgs.EMPTY_LOCK,
'0x0000000000000000'
)
const tx: Transaction = Transaction.fromObject({
version: '0',
cellDeps: [cellDep, daoCellDep],
Expand Down
1 change: 1 addition & 0 deletions packages/neuron-wallet/src/utils/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const DEFAULT_ARGS_LENGTH = 42
export const LOCKTIME_ARGS_LENGTH = 58
export const CHEQUE_ARGS_LENGTH = 82
export const CKB_NODE_DATA_SIZE_BUFFER_RATIO = 1.2
export const DAO_DATA = '0x0000000000000000'

export enum ResponseCode {
Fail,
Expand Down
Loading