From 90fab7f29b37f293a71c70d3b368d9cd5d458faf Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Fri, 4 Sep 2020 10:26:39 +0200 Subject: [PATCH] Individual slash cancel (#3605) * Individual slash cancel * Optional buttonrow --- package.json | 6 +- packages/page-contracts/package.json | 2 +- .../page-council/src/Motions/Slashing.tsx | 30 ++-- packages/page-staking/src/Slashes/Era.tsx | 57 +++++++- packages/page-staking/src/Slashes/Row.tsx | 21 ++- packages/page-staking/src/Slashes/Summary.tsx | 6 +- packages/page-staking/src/Slashes/index.tsx | 20 ++- packages/react-api/package.json | 4 +- yarn.lock | 132 +++++++++--------- 9 files changed, 179 insertions(+), 99 deletions(-) diff --git a/package.json b/package.json index 0779e16dab..dd5ece07ea 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,10 @@ "afterSign": "electron-builder-notarize" }, "resolutions": { - "@polkadot/api": "^1.32.0-beta.16", - "@polkadot/api-contract": "^1.32.0-beta.16", + "@polkadot/api": "^1.32.0-beta.18", + "@polkadot/api-contract": "^1.32.0-beta.18", "@polkadot/keyring": "^3.4.1", - "@polkadot/types": "^1.32.0-beta.16", + "@polkadot/types": "^1.32.0-beta.18", "@polkadot/util": "^3.4.1", "@polkadot/util-crypto": "^3.4.1", "@polkadot/wasm-crypto": "^1.4.1", diff --git a/packages/page-contracts/package.json b/packages/page-contracts/package.json index 4ea04ac68b..1d30850f95 100644 --- a/packages/page-contracts/package.json +++ b/packages/page-contracts/package.json @@ -12,6 +12,6 @@ "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.11.2", - "@polkadot/api-contract": "^1.32.0-beta.16" + "@polkadot/api-contract": "^1.32.0-beta.18" } } diff --git a/packages/page-council/src/Motions/Slashing.tsx b/packages/page-council/src/Motions/Slashing.tsx index f32d44f085..1f66d17eac 100644 --- a/packages/page-council/src/Motions/Slashing.tsx +++ b/packages/page-council/src/Motions/Slashing.tsx @@ -4,7 +4,7 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { Button, Dropdown, Input, InputAddress, Modal, TxButton } from '@polkadot/react-components'; import { useApi, useAvailableSlashes, useToggle } from '@polkadot/react-hooks'; @@ -34,27 +34,25 @@ function Slashing ({ className = '', isMember, members }: Props): React.ReactEle const [isVisible, toggleVisible] = useToggle(); const [accountId, setAcountId] = useState(null); const [{ proposal, proposalLength }, setProposal] = useState({ proposal: null, proposalLength: 0 }); - const [eras, setEras] = useState([]); const [selectedEra, setSelectedEra] = useState(0); const threshold = Math.ceil((members.length || 0) * getSlashThreshold(api)); - useEffect((): void => { - setEras( - (slashes || []).map(([era, slashes]): Option => ({ - text: t('era {{era}}, {{count}} slashes', { - replace: { - count: slashes.length, - era: era.toNumber() - } - }), - value: era.toNumber() - })) - ); - }, [slashes, t]); + const eras = useMemo( + () => (slashes || []).map(([era, slashes]): Option => ({ + text: t('era {{era}}, {{count}} slashes', { + replace: { + count: slashes.length, + era: era.toNumber() + } + }), + value: era.toNumber() + })), + [slashes, t] + ); useEffect((): void => { - const actioned = selectedEra && slashes && slashes.find(([era]): boolean => era.eqn(selectedEra)); + const actioned = selectedEra && slashes && slashes.find(([era]) => era.eqn(selectedEra)); const proposal = actioned ? api.tx.staking.cancelDeferredSlash(actioned[0], actioned[1].map((_, index): number => index)) : null; diff --git a/packages/page-staking/src/Slashes/Era.tsx b/packages/page-staking/src/Slashes/Era.tsx index 15dd30949b..3d1552340e 100644 --- a/packages/page-staking/src/Slashes/Era.tsx +++ b/packages/page-staking/src/Slashes/Era.tsx @@ -2,21 +2,32 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. +import { SubmittableExtrinsic } from '@polkadot/api/types'; import { SlashEra } from './types'; -import React, { useRef } from 'react'; -import { Table } from '@polkadot/react-components'; +import React, { useCallback, useRef, useState } from 'react'; +import { Button, Table, TxButton } from '@polkadot/react-components'; +import { useApi } from '@polkadot/react-hooks'; import { useTranslation } from '../translate'; import Row from './Row'; import Summary from './Summary'; interface Props { + councilId: string | null; + councilThreshold: number; slash: SlashEra; } -function Slashes ({ slash }: Props): React.ReactElement | null { +interface Selected { + selected: number[]; + tx: SubmittableExtrinsic<'promise'> | null; +} + +function Slashes ({ councilId, councilThreshold, slash }: Props): React.ReactElement | null { const { t } = useTranslation(); + const { api } = useApi(); + const [{ selected, tx }, setSelected] = useState({ selected: [], tx: null }); const headerRef = useRef<[string?, string?, number?][]>([ [undefined, 'start', 3], @@ -24,12 +35,41 @@ function Slashes ({ slash }: Props): React.ReactElement | null { [t('own')], [t('other')], [t('total')], - [t('payout')] + [t('payout')], + [] ]); + const _onSelect = useCallback( + (index: number) => setSelected((state): Selected => { + const selected = state.selected.includes(index) + ? state.selected.filter((i) => i !== index) + : state.selected.concat(index).sort((a, b) => a - b); + const proposal = selected.length + ? api.tx.staking.cancelDeferredSlash(slash.era, selected) + : null; + const tx = proposal + ? api.tx.council.propose(councilThreshold, proposal, proposal.encodedLength) + : null; + + return { selected, tx }; + }), + [api, councilThreshold, slash] + ); + return ( - + + {councilId && ( + + + + )} + {headerRef.current.map(([label, className, colSpan = 1], index): React.ReactNode => ( {slash.slashes.map((slash, index): React.ReactNode => ( ))} diff --git a/packages/page-staking/src/Slashes/Row.tsx b/packages/page-staking/src/Slashes/Row.tsx index a42d3fa474..5f3c1939bd 100644 --- a/packages/page-staking/src/Slashes/Row.tsx +++ b/packages/page-staking/src/Slashes/Row.tsx @@ -4,20 +4,28 @@ import { Slash } from './types'; -import React from 'react'; -import { AddressMini, AddressSmall, Badge, Expander } from '@polkadot/react-components'; +import React, { useCallback } from 'react'; +import { AddressMini, AddressSmall, Badge, Checkbox, Expander } from '@polkadot/react-components'; import { FormatBalance } from '@polkadot/react-query'; import { formatNumber } from '@polkadot/util'; import { useTranslation } from '../translate'; interface Props { + index: number; + isSelected: boolean; + onSelect?: (index: number) => void; slash: Slash; } -function Row ({ slash: { isMine, slash: { others, own, payout, reporters, validator }, total, totalOther } }: Props): React.ReactElement { +function Row ({ index, isSelected, onSelect, slash: { isMine, slash: { others, own, payout, reporters, validator }, total, totalOther } }: Props): React.ReactElement { const { t } = useTranslation(); + const _onSelect = useCallback( + () => onSelect && onSelect(index), + [index, onSelect] + ); + return ( + ); } diff --git a/packages/page-staking/src/Slashes/Summary.tsx b/packages/page-staking/src/Slashes/Summary.tsx index 7171119f4a..3af598bdd9 100644 --- a/packages/page-staking/src/Slashes/Summary.tsx +++ b/packages/page-staking/src/Slashes/Summary.tsx @@ -15,10 +15,11 @@ import { formatNumber } from '@polkadot/util'; import { useTranslation } from '../translate'; interface Props { + children: React.ReactNode; slash: SlashEra; } -function Header ({ slash: { era, nominators, reporters, total, validators } }: Props): React.ReactElement | null { +function Header ({ children, slash: { era, nominators, reporters, total, validators } }: Props): React.ReactElement | null { const { t } = useTranslation(); const { api } = useApi(); const sessionInfo = useCall(api.derive.session?.progress); @@ -35,7 +36,7 @@ function Header ({ slash: { era, nominators, reporters, total, validators } }: P return ( - ); diff --git a/packages/page-staking/src/Slashes/index.tsx b/packages/page-staking/src/Slashes/index.tsx index f92a0209c8..9e8b66df17 100644 --- a/packages/page-staking/src/Slashes/index.tsx +++ b/packages/page-staking/src/Slashes/index.tsx @@ -9,6 +9,8 @@ import { Slash, SlashEra } from './types'; import BN from 'bn.js'; import React, { useMemo } from 'react'; import { Table } from '@polkadot/react-components'; +import { useAccounts, useApi, useMembers } from '@polkadot/react-hooks'; +import { getSlashThreshold } from '@polkadot/app-council/thresholds'; import { useTranslation } from '../translate'; import Era from './Era'; @@ -85,7 +87,19 @@ function calcSlashEras (slashes: [BN, UnappliedSlash[]][], ownStashes: StakerSta function Slashes ({ ownStashes = [], slashes }: Props): React.ReactElement | null { const { t } = useTranslation(); - const rows = useMemo(() => calcSlashEras(slashes, ownStashes), [ownStashes, slashes]); + const { api } = useApi(); + const { allAccounts } = useAccounts(); + const { members } = useMembers(); + + const rows = useMemo( + () => calcSlashEras(slashes, ownStashes), + [ownStashes, slashes] + ); + + const councilId = useMemo( + () => allAccounts.find((accountId) => members.includes(accountId)) || null, + [allAccounts, members] + ); if (!rows.length) { return ( @@ -96,10 +110,14 @@ function Slashes ({ ownStashes = [], slashes }: Props): React.ReactElement {rows.map((slash): React.ReactNode => ( diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 3e5bace0bf..10447ebdcb 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -31,8 +31,8 @@ "homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme", "dependencies": { "@babel/runtime": "^7.11.2", - "@polkadot/api": "^1.32.0-beta.16", - "@polkadot/extension-dapp": "^0.33.0-beta.12", + "@polkadot/api": "^1.32.0-beta.18", + "@polkadot/extension-dapp": "^0.33.0-beta.17", "rxjs-compat": "^6.6.2" } } diff --git a/yarn.lock b/yarn.lock index 31b3e30ce4..121c863ee9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3248,57 +3248,57 @@ __metadata: languageName: node linkType: hard -"@polkadot/api-contract@npm:^1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/api-contract@npm:1.32.0-beta.16" +"@polkadot/api-contract@npm:^1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/api-contract@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/api": 1.32.0-beta.16 - "@polkadot/rpc-core": 1.32.0-beta.16 - "@polkadot/types": 1.32.0-beta.16 + "@polkadot/api": 1.32.0-beta.18 + "@polkadot/rpc-core": 1.32.0-beta.18 + "@polkadot/types": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 bn.js: ^5.1.3 rxjs: ^6.6.2 - checksum: 3a837b8b4feb9aba8b52e09f1a1b75eb35427d331b4d027c94cf9d2d9ff9da86a10f0407aa5477e0790f3205db505c80ae2385663880d0db91721712c6739629 + checksum: 923173a52b318fab8ddbb753b125ab37cd63290eb3bd9d443dde37ec526232d3abe953fd87a6b378541762937fffe5406d49b9334a53d6a0fa69e009837dd21a languageName: node linkType: hard -"@polkadot/api-derive@npm:1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/api-derive@npm:1.32.0-beta.16" +"@polkadot/api-derive@npm:1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/api-derive@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/api": 1.32.0-beta.16 - "@polkadot/rpc-core": 1.32.0-beta.16 - "@polkadot/rpc-provider": 1.32.0-beta.16 - "@polkadot/types": 1.32.0-beta.16 + "@polkadot/api": 1.32.0-beta.18 + "@polkadot/rpc-core": 1.32.0-beta.18 + "@polkadot/rpc-provider": 1.32.0-beta.18 + "@polkadot/types": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 "@polkadot/util-crypto": ^3.4.1 bn.js: ^5.1.3 memoizee: ^0.4.14 rxjs: ^6.6.2 - checksum: 31fecf459b63df84396f127410f20af091d65791df43fac513dedadc08c10b425ee4a570c906ca613f72e98e3c1c95ba5e8745160a91b3005155911e8a0eca17 + checksum: 9d6ebb0ed02a0f969aa82192acad567c7907be23d568c8aa1d8ce84f5d4638e66e6a3c0cb3f856cc993d66a98a407c20cc4c7f06b233b9f2b1ad2cd24d5594ab languageName: node linkType: hard -"@polkadot/api@npm:^1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/api@npm:1.32.0-beta.16" +"@polkadot/api@npm:^1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/api@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/api-derive": 1.32.0-beta.16 + "@polkadot/api-derive": 1.32.0-beta.18 "@polkadot/keyring": ^3.4.1 - "@polkadot/metadata": 1.32.0-beta.16 - "@polkadot/rpc-core": 1.32.0-beta.16 - "@polkadot/rpc-provider": 1.32.0-beta.16 - "@polkadot/types": 1.32.0-beta.16 - "@polkadot/types-known": 1.32.0-beta.16 + "@polkadot/metadata": 1.32.0-beta.18 + "@polkadot/rpc-core": 1.32.0-beta.18 + "@polkadot/rpc-provider": 1.32.0-beta.18 + "@polkadot/types": 1.32.0-beta.18 + "@polkadot/types-known": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 "@polkadot/util-crypto": ^3.4.1 bn.js: ^5.1.3 eventemitter3: ^4.0.7 rxjs: ^6.6.2 - checksum: 8e6297753a801d34fb30fd1ad52394dc9d848f19abfa0441b93dcc23434195a834c9d4bf8588779aca565d7af4e70a07360b6583f2715b8028046ca692e6e5b4 + checksum: 7d197efc12d9eb20f04d4a2dd6df3df7fab9615c2e6fb07ac8070cf91aa53d6585830f5922081fdc1128b757ce1dbbb54bff3505d09dd363353c9dbb78fdca9c languageName: node linkType: hard @@ -3354,7 +3354,7 @@ __metadata: resolution: "@polkadot/app-contracts@workspace:packages/page-contracts" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/api-contract": ^1.32.0-beta.16 + "@polkadot/api-contract": ^1.32.0-beta.18 languageName: unknown linkType: soft @@ -3702,28 +3702,28 @@ __metadata: languageName: node linkType: hard -"@polkadot/extension-dapp@npm:^0.33.0-beta.12": - version: 0.33.0-beta.12 - resolution: "@polkadot/extension-dapp@npm:0.33.0-beta.12" +"@polkadot/extension-dapp@npm:^0.33.0-beta.17": + version: 0.33.0-beta.17 + resolution: "@polkadot/extension-dapp@npm:0.33.0-beta.17" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/extension-inject": 0.33.0-beta.12 + "@polkadot/extension-inject": 0.33.0-beta.17 "@polkadot/util": ^3.4.1 "@polkadot/util-crypto": ^3.4.1 peerDependencies: "@polkadot/api": "*" - checksum: 0150f71f7ebf4e0e1e4ad6cfaa56169cbb59258a803b669cb005476a12bb58375791ea30ce0592c1632c7d574180405b8a0ee5729bd4f33d3c26186cbb16a41c + checksum: 5c6d2d749d5a01a024d982777718fa2418e11d4ba9eae28f82f09e3b3c0ec47367923a0a60d3a86d79e318d1f6a6e9fea143db30fdc86ced0649e9d0dd4c0024 languageName: node linkType: hard -"@polkadot/extension-inject@npm:0.33.0-beta.12": - version: 0.33.0-beta.12 - resolution: "@polkadot/extension-inject@npm:0.33.0-beta.12" +"@polkadot/extension-inject@npm:0.33.0-beta.17": + version: 0.33.0-beta.17 + resolution: "@polkadot/extension-inject@npm:0.33.0-beta.17" dependencies: "@babel/runtime": ^7.11.2 peerDependencies: "@polkadot/api": "*" - checksum: f0526e95cacebef9fee4018f23d14cafe02fa2d01f66ad869f9067da47a48990261188af5b4e36c5b860379039d9d25b22943598f657a36638a09fab97e3c808 + checksum: b4f4a7a39d9bf25ac36dcb92dd2cb7222163906048655f8dece7bd744228f5545675f2b3667c0556e8f36756c776930224ceb619ae38b06210895efebf122561 languageName: node linkType: hard @@ -3738,17 +3738,17 @@ __metadata: languageName: node linkType: hard -"@polkadot/metadata@npm:1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/metadata@npm:1.32.0-beta.16" +"@polkadot/metadata@npm:1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/metadata@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/types": 1.32.0-beta.16 - "@polkadot/types-known": 1.32.0-beta.16 + "@polkadot/types": 1.32.0-beta.18 + "@polkadot/types-known": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 "@polkadot/util-crypto": ^3.4.1 bn.js: ^5.1.3 - checksum: bd6f00771bdf241adb7309b26cad993433ad0c6d6c109d86795f6787a5fb1b32df5d305ac31f94f4b290955765bdae7f382dda96151c1b70c8cb931c899af0f4 + checksum: cc36a0e045c5d634d23698f458e7c140ff4e30472382f3e1c9d37e57b03080b289aedb50404f5fbbfd1235033cf2501634f0714db5f17d84e62139581f7b2b0e languageName: node linkType: hard @@ -3757,8 +3757,8 @@ __metadata: resolution: "@polkadot/react-api@workspace:packages/react-api" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/api": ^1.32.0-beta.16 - "@polkadot/extension-dapp": ^0.33.0-beta.12 + "@polkadot/api": ^1.32.0-beta.18 + "@polkadot/extension-dapp": ^0.33.0-beta.17 rxjs-compat: ^6.6.2 languageName: unknown linkType: soft @@ -3880,35 +3880,35 @@ __metadata: languageName: unknown linkType: soft -"@polkadot/rpc-core@npm:1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/rpc-core@npm:1.32.0-beta.16" +"@polkadot/rpc-core@npm:1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/rpc-core@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/metadata": 1.32.0-beta.16 - "@polkadot/rpc-provider": 1.32.0-beta.16 - "@polkadot/types": 1.32.0-beta.16 + "@polkadot/metadata": 1.32.0-beta.18 + "@polkadot/rpc-provider": 1.32.0-beta.18 + "@polkadot/types": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 memoizee: ^0.4.14 rxjs: ^6.6.2 - checksum: ad6207e0436b4ff64e8f9f8e51ef02faa53bbb1d9a66bf28fea99bba7b30e4a852b883d5b44973e42ea1e651b13146209cea41dc74bd47a3a6d373dd2b9e93e3 + checksum: 549397b17856459020630a093a9721bf95540d487c33c40c88b75c21186c4ffa3bbf5eec1372035a17f1d1e2eafc179a389da9141ba31b3a4f517f5847b32c21 languageName: node linkType: hard -"@polkadot/rpc-provider@npm:1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/rpc-provider@npm:1.32.0-beta.16" +"@polkadot/rpc-provider@npm:1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/rpc-provider@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/metadata": 1.32.0-beta.16 - "@polkadot/types": 1.32.0-beta.16 + "@polkadot/metadata": 1.32.0-beta.18 + "@polkadot/types": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 "@polkadot/util-crypto": ^3.4.1 bn.js: ^5.1.3 eventemitter3: ^4.0.7 isomorphic-fetch: ^2.2.1 websocket: ^1.0.32 - checksum: f290504e0a11fa749faf2eb071a0f0909e25c4ee657dea529c2a4cb7d2bf2aca90e9eb1005b96179814c9cfaee8778a2ecaf88576939344e58cf4ad5a8362e9a + checksum: d75760d69667519fbe6dfaa33447c7e0b506ceb276f089c612454a7b11b76da9a1b19e8b7d3afba7d5ab29b1a6bdc019e7545f5de99538ab6923a3740035d5b4 languageName: node linkType: hard @@ -3921,31 +3921,31 @@ __metadata: languageName: node linkType: hard -"@polkadot/types-known@npm:1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/types-known@npm:1.32.0-beta.16" +"@polkadot/types-known@npm:1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/types-known@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/types": 1.32.0-beta.16 + "@polkadot/types": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 bn.js: ^5.1.3 - checksum: 7d9c0398a7a37f7027b58a347ca4acca3210b961699108e108dcd058aac63d0cb5493b8f7540c03faeb246f8a99c05c7f0b48fe60e39ffcd54ea040c9f322800 + checksum: f39a400ce0dbcafc8c7d8b86c4227ddda5504bacaa70f9a507bdfc4fd4dd57ce19f9893990b8b7403d0db9f3056cf34061ee75e7fe77a72546c69d3e24ad43d6 languageName: node linkType: hard -"@polkadot/types@npm:^1.32.0-beta.16": - version: 1.32.0-beta.16 - resolution: "@polkadot/types@npm:1.32.0-beta.16" +"@polkadot/types@npm:^1.32.0-beta.18": + version: 1.32.0-beta.18 + resolution: "@polkadot/types@npm:1.32.0-beta.18" dependencies: "@babel/runtime": ^7.11.2 - "@polkadot/metadata": 1.32.0-beta.16 + "@polkadot/metadata": 1.32.0-beta.18 "@polkadot/util": ^3.4.1 "@polkadot/util-crypto": ^3.4.1 "@types/bn.js": ^4.11.6 bn.js: ^5.1.3 memoizee: ^0.4.14 rxjs: ^6.6.2 - checksum: 3b82db773304b7c6d66be05a8993e162246d41f2f4a5213aaf9bf9d9dcaeaeed11eb2d78e9fad658ab3a350f9667a64f18cc292c0fd59eb4f5eee8b0caf7cb40 + checksum: f68ca0d6aff2ff7dd59880eeae37c2622c5571f7d170800645d74b85281269d34cf0603e2a07b78d065578041d4f18736de768f948fdfa85180bef8b48b2cb87 languageName: node linkType: hard
| null {
@@ -65,6 +73,13 @@ function Row ({ slash: { isMine, slash: { others, own, payout, reporters, valida + +
+
('validators')}> @@ -66,6 +67,7 @@ function Header ({ slash: { era, nominators, reporters, total, validators } }: P
+ {children}