diff --git a/package.json b/package.json index 4948170447..cc2352151d 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,9 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@ledgerhq/hw-transport-webhid": "^6.27.19", "@polkadot-cloud/assets": "^0.1.24", - "@polkadot-cloud/core": "^1.0.26", + "@polkadot-cloud/core": "^1.0.29", "@polkadot-cloud/react": "^0.1.97", - "@polkadot-cloud/utils": "^0.0.22", + "@polkadot-cloud/utils": "^0.0.23", "@polkadot/api": "^10.10.1", "@polkadot/keyring": "^12.1.1", "@polkadot/rpc-provider": "^10.9.1", @@ -69,18 +69,18 @@ "@types/react-helmet": "^6.1.8", "@types/react-qr-reader": "^2.1.6", "@types/react-scroll": "^1.8.9", - "@typescript-eslint/eslint-plugin": "^6.8.0", - "@typescript-eslint/parser": "^6.8.0", + "@typescript-eslint/eslint-plugin": "^6.9.0", + "@typescript-eslint/parser": "^6.9.0", "@vitejs/plugin-react-swc": "^3.4.0", "eslint": "^8.52.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-import": "^2.28.1", + "eslint-plugin-import": "^2.29.0", "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-prefer-arrow": "^1.2.3", - "eslint-plugin-prefer-arrow-functions": "^3.1.4", + "eslint-plugin-prefer-arrow-functions": "^3.2.4", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-unused-imports": "^3.0.0", diff --git a/src/Providers.tsx b/src/Providers.tsx index 1272a51858..e29983d323 100644 --- a/src/Providers.tsx +++ b/src/Providers.tsx @@ -48,6 +48,7 @@ import { OtherAccountsProvider } from 'contexts/Connect/OtherAccounts'; import { useActiveAccounts } from 'contexts/ActiveAccounts'; import { DappName } from 'consts'; import { ImportedAccountsProvider } from 'contexts/Connect/ImportedAccounts'; +import { PoolPerformanceProvider } from 'contexts/Pools/PoolPerformance'; // Embed providers from hook. export const Providers = () => { @@ -91,6 +92,7 @@ export const Providers = () => { FavoriteValidatorsProvider, FastUnstakeProvider, PayoutsProvider, + PoolPerformanceProvider, UIProvider, SetupProvider, MenuProvider, diff --git a/src/consts.ts b/src/consts.ts index 2712aee007..ff7511dfd8 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -54,8 +54,8 @@ export const FallbackEpochDuration = new BigNumber(2400); /* * Misc values */ -export const ListItemsPerPage = 30; -export const ListItemsPerBatch = 30; +export const ListItemsPerPage = 25; +export const ListItemsPerBatch = 25; export const MinBondPrecision = 3; export const MaxPayoutDays = 60; export const MaxEraRewardPointsEras = 14; diff --git a/src/contexts/Pools/BondedPools/index.tsx b/src/contexts/Pools/BondedPools/index.tsx index 338bf441dc..df6330040e 100644 --- a/src/contexts/Pools/BondedPools/index.tsx +++ b/src/contexts/Pools/BondedPools/index.tsx @@ -25,44 +25,20 @@ export const BondedPoolsProvider = ({ }) => { const { network } = useNetwork(); const { api, isReady } = useApi(); - const { getNominationsStatusFromTargets } = useStaking(); const { createAccounts, stats } = usePoolsConfig(); + const { getNominationsStatusFromTargets } = useStaking(); const { lastPoolId } = stats; - // stores the meta data batches for pool lists + // Stores the meta data batches for pool lists. const [poolMetaBatches, setPoolMetaBatch]: AnyMetaBatch = useState({}); const poolMetaBatchesRef = useRef(poolMetaBatches); - // stores the meta batch subscriptions for pool lists + // Stores the meta batch subscriptions for pool lists. const poolSubs = useRef>({}); - // store bonded pools + // Store bonded pools. const [bondedPools, setBondedPools] = useState([]); - // clear existing state for network refresh - useEffectIgnoreInitial(() => { - setBondedPools([]); - setStateWithRef({}, setPoolMetaBatch, poolMetaBatchesRef); - }, [network]); - - // initial setup for fetching bonded pools - useEffectIgnoreInitial(() => { - if (isReady) { - // fetch bonded pools - fetchBondedPools(); - } - return () => { - unsubscribe(); - }; - }, [network, isReady, lastPoolId]); - - // after bonded pools have synced, fetch metabatch - useEffectIgnoreInitial(() => { - if (bondedPools.length) { - fetchPoolsMetaBatch('bonded_pools', bondedPools, true); - } - }, [bondedPools]); - const unsubscribe = () => { Object.values(poolSubs.current).map((batch: Fn[]) => Object.entries(batch).map(([, v]) => v()) @@ -122,12 +98,8 @@ export const BondedPoolsProvider = ({ p: AnyMetaBatch, refetch = false ) => { - if (!isReady || !api) { - return; - } - if (!p.length) { - return; - } + if (!isReady || !api || !p.length) return; + if (!refetch) { // if already exists, do not re-fetch if (poolMetaBatchesRef.current[key] !== undefined) { @@ -344,9 +316,8 @@ export const BondedPoolsProvider = ({ }; const updateBondedPools = (updatedPools: BondedPool[]) => { - if (!updatedPools) { - return; - } + if (!updatedPools) return; + setBondedPools( bondedPools.map( (original) => @@ -365,9 +336,7 @@ export const BondedPoolsProvider = ({ if (!pool) return; const exists = bondedPools.find((b) => b.id === pool.id); - if (!exists) { - setBondedPools(bondedPools.concat(pool)); - } + if (!exists) setBondedPools(bondedPools.concat(pool)); }; // get all the roles belonging to one pool account @@ -461,6 +430,26 @@ export const BondedPoolsProvider = ({ setBondedPools(newBondedPools); }; + // Clear existing state for network refresh. + useEffectIgnoreInitial(() => { + setBondedPools([]); + setStateWithRef({}, setPoolMetaBatch, poolMetaBatchesRef); + }, [network]); + + // Initial setup for fetching bonded pools. + useEffectIgnoreInitial(() => { + if (isReady) fetchBondedPools(); + return () => { + unsubscribe(); + }; + }, [network, isReady, lastPoolId]); + + // After bonded pools have synced, fetch metabatch. + useEffectIgnoreInitial(() => { + if (bondedPools.length) + fetchPoolsMetaBatch('bonded_pools', bondedPools, true); + }, [bondedPools]); + return ( { + const { api } = useApi(); + const { network } = useNetwork(); + const { bondedPools } = useBondedPools(); + const { activeEra } = useNetworkMetrics(); + const { erasRewardPointsFetched, erasRewardPoints } = useValidators(); + + // Store whether pool performance data is being fetched. + const [poolRewardPointsFetched, setPoolRewardPointsFetched] = + useState('unsynced'); + + // Store pool performance data. + const [poolRewardPoints, setPoolRewardPoints] = useState< + Record> + >({}); + + // Store the currently active era being processed for pool performance. + const [currentEra, setCurrentEra] = useState(new BigNumber(0)); + + // Store the earliest era that should be processed. + const [finishEra, setFinishEra] = useState(new BigNumber(0)); + + // Handle worker message on completed exposure check. + worker.onmessage = (message: MessageEvent) => { + if (message) { + const { data } = message; + const { task } = data; + if (task !== 'processNominationPoolsRewardData') return; + + // Update state with new data. + const { poolRewardData } = data; + setPoolRewardPoints(mergeDeep(poolRewardPoints, poolRewardData)); + + if (currentEra.isEqualTo(finishEra)) { + setPoolRewardPointsFetched('synced'); + } else { + const nextEra = BigNumber.max(currentEra.minus(1), 1); + processEra(nextEra); + } + } + }; + + // Start fetching pool performance calls from the current era. + const startGetPoolPerformance = async () => { + setPoolRewardPointsFetched('syncing'); + setFinishEra( + BigNumber.max(activeEra.index.minus(MaxEraRewardPointsEras), 1) + ); + const startEra = BigNumber.max(activeEra.index.minus(1), 1); + processEra(startEra); + }; + + // Get era data and send to worker. + const processEra = async (era: BigNumber) => { + if (!api) return; + setCurrentEra(era); + const result = await api.query.staking.erasStakersClipped.entries( + era.toString() + ); + const exposures = formatRawExposures(result); + worker.postMessage({ + task: 'processNominationPoolsRewardData', + era: era.toString(), + exposures, + bondedPools: bondedPools.map((b) => b.addresses.stash), + erasRewardPoints, + }); + }; + + // Trigger worker to calculate pool reward data for garaphs once: + // + // - active era is synced. + // - era reward points are fetched. + // - bonded pools have been fetched. + // + // Re-calculates when any of the above change. + useEffectIgnoreInitial(() => { + if ( + api && + bondedPools.length && + activeEra.index.isGreaterThan(0) && + erasRewardPointsFetched === 'synced' && + poolRewardPointsFetched === 'unsynced' + ) { + startGetPoolPerformance(); + } + }, [ + bondedPools, + activeEra, + erasRewardPointsFetched, + poolRewardPointsFetched, + ]); + + // Reset state data on network change. + useEffectIgnoreInitial(() => { + setPoolRewardPoints({}); + setCurrentEra(new BigNumber(0)); + setFinishEra(new BigNumber(0)); + setPoolRewardPointsFetched('unsynced'); + }, [network]); + + return ( + + {children} + + ); +}; + +export const PoolPerformanceContext = + React.createContext( + defaultPoolPerformanceContext + ); + +export const usePoolPerformance = () => + React.useContext(PoolPerformanceContext); diff --git a/src/contexts/Pools/PoolPerformance/types.ts b/src/contexts/Pools/PoolPerformance/types.ts new file mode 100644 index 0000000000..acef8792bb --- /dev/null +++ b/src/contexts/Pools/PoolPerformance/types.ts @@ -0,0 +1,10 @@ +// Copyright 2023 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import type { AnyJson } from '@polkadot-cloud/react/types'; +import type { Sync } from 'types'; + +export interface PoolPerformanceContextInterface { + poolRewardPointsFetched: Sync; + poolRewardPoints: AnyJson; +} diff --git a/src/contexts/UI/index.tsx b/src/contexts/UI/index.tsx index a736c42066..6050f890cb 100644 --- a/src/contexts/UI/index.tsx +++ b/src/contexts/UI/index.tsx @@ -132,9 +132,9 @@ export const UIProvider = ({ children }: { children: React.ReactNode }) => { setSideMenuOpen(v); }; - const [containerRefs, _setContainerRefs] = useState({}); + const [containerRefs, setContainerRefsState] = useState({}); const setContainerRefs = (v: any) => { - _setContainerRefs(v); + setContainerRefsState(v); }; return ( diff --git a/src/library/ListItem/Labels/PoolBonded.tsx b/src/library/ListItem/Labels/PoolBonded.tsx index 8d9d2031f4..e2a12a473c 100644 --- a/src/library/ListItem/Labels/PoolBonded.tsx +++ b/src/library/ListItem/Labels/PoolBonded.tsx @@ -77,7 +77,7 @@ export const PoolBonded = ({ return ( <> - +
{nominationStatus === null || !eraStakers.stakers.length ? `${t('syncing')}...` diff --git a/src/library/ListItem/Wrappers.ts b/src/library/ListItem/Wrappers.ts index 58c7dd2b52..58035beb2f 100644 --- a/src/library/ListItem/Wrappers.ts +++ b/src/library/ListItem/Wrappers.ts @@ -9,10 +9,12 @@ export const Wrapper = styled.div` --height-top-row: 3.25rem; --height-bottom-row: 5rem; - &.pool, &.member { --height-bottom-row: 2.75rem; } + &.pool-join { + --height-bottom-row: 7.5rem; + } --height-total: calc(var(--height-top-row) + var(--height-bottom-row)); @@ -139,16 +141,20 @@ export const Labels = styled.div` margin-right: 0; button { - color: var(--accent-color-primary); - background: none; + color: var(--accent-color-secondary); + font-family: InterSemiBold, sans-serif; font-size: 0.95rem; display: flex; flex-flow: row wrap; align-items: center; width: auto; height: auto; - border-radius: none; + border-radius: 0.75rem; + padding: 0.25rem 0.75rem; + &:hover { + opacity: 1; + } > svg { margin-left: 0.3rem; } @@ -338,9 +344,9 @@ export const ValidatorPulseWrapper = styled.div` var(--shimmer-foreground) 100% ); background-repeat: no-repeat; - background-size: 600px 104px; + background-size: 500px 104px; animation-duration: 1.5s; - opacity: 0.15; + opacity: 0.2; animation-fill-mode: forwards; animation-iteration-count: infinite; animation-name: shimmer; diff --git a/src/library/Pool/Rewards.tsx b/src/library/Pool/Rewards.tsx new file mode 100644 index 0000000000..11ac4d90e6 --- /dev/null +++ b/src/library/Pool/Rewards.tsx @@ -0,0 +1,165 @@ +// Copyright 2023 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only + +import BigNumber from 'bignumber.js'; +import { useValidators } from 'contexts/Validators/ValidatorEntries'; +import { + TooltipTrigger, + ValidatorPulseWrapper, +} from 'library/ListItem/Wrappers'; +import { useTooltip } from 'contexts/Tooltip'; +import { MaxEraRewardPointsEras } from 'consts'; +import { useApi } from 'contexts/Api'; +import { + normaliseEraPoints, + prefillEraPoints, +} from 'library/ValidatorList/ValidatorItem/Utils'; +import type { AnyJson } from '@polkadot-cloud/react/types'; +import { usePoolPerformance } from 'contexts/Pools/PoolPerformance'; +import { useTranslation } from 'react-i18next'; +import type { RewardProps, RewardsGraphProps } from './types'; + +export const Rewards = ({ address, displayFor = 'default' }: RewardProps) => { + const { t } = useTranslation('library'); + const { isReady } = useApi(); + const { setTooltipTextAndOpen } = useTooltip(); + const { eraPointsBoundaries } = useValidators(); + const { poolRewardPoints, poolRewardPointsFetched } = usePoolPerformance(); + + const eraRewardPoints = Object.fromEntries( + Object.entries(poolRewardPoints[address] || {}).map(([k, v]: AnyJson) => [ + k, + new BigNumber(v), + ]) + ); + + const high = eraPointsBoundaries?.high || new BigNumber(1); + const normalisedPoints = normaliseEraPoints(eraRewardPoints, high); + const prefilledPoints = prefillEraPoints(Object.values(normalisedPoints)); + + const empty = Object.values(poolRewardPoints).length === 0; + const syncing = !isReady || poolRewardPointsFetched !== 'synced'; + const tooltipText = `${MaxEraRewardPointsEras} ${t('dayPoolPerformance')}`; + + return ( + + {syncing &&
} + setTooltipTextAndOpen(tooltipText)} + /> + + + ); +}; + +export const RewardsGraph = ({ points = [], syncing }: RewardsGraphProps) => { + const totalSegments = points.length - 1; + const vbWidth = 512; + const vbHeight = 115; + const xPadding = 5; + const yPadding = 10; + const xArea = vbWidth - 2 * xPadding; + const yArea = vbHeight - 2 * yPadding; + const xSegment = xArea / totalSegments; + let xCursor = xPadding; + + const pointsCoords = points.map((point: number) => { + const coord = { + x: xCursor, + y: vbHeight - yPadding - yArea * point, + zero: point === 0, + }; + xCursor += xSegment; + return coord; + }); + + const lineCoords = []; + for (let i = 0; i <= pointsCoords.length - 1; i++) { + const startZero = pointsCoords[i].zero; + const endZero = pointsCoords[i + 1]?.zero; + + lineCoords.push({ + x1: pointsCoords[i].x, + y1: pointsCoords[i].y, + x2: pointsCoords[i + 1]?.x || pointsCoords[i].x, + y2: pointsCoords[i + 1]?.y || pointsCoords[i].y, + zero: startZero && endZero, + }); + } + + const barCoords = []; + for (let i = 0; i <= pointsCoords.length - 1; i++) { + barCoords.push({ + x1: pointsCoords[i].x, + y1: vbHeight - yPadding, + x2: pointsCoords[i].x, + y2: pointsCoords[i]?.y, + }); + } + + return ( + + {!syncing && + [{ y1: vbHeight * 0.5, y2: vbHeight * 0.5 }].map( + ({ y1, y2 }, index) => { + return ( + + ); + } + )} + + {!syncing && + barCoords.map(({ x1, y1, x2, y2 }, index) => { + return ( + + ); + })} + + {!syncing && + lineCoords.map(({ x1, y1, x2, y2, zero }, index) => { + return ( + + ); + })} + + ); +}; diff --git a/src/library/Pool/index.tsx b/src/library/Pool/index.tsx index b4780aac49..98ed0be7f7 100644 --- a/src/library/Pool/index.tsx +++ b/src/library/Pool/index.tsx @@ -32,6 +32,7 @@ import { JoinPool } from '../ListItem/Labels/JoinPool'; import { Members } from '../ListItem/Labels/Members'; import { PoolId } from '../ListItem/Labels/PoolId'; import type { PoolProps } from './types'; +import { Rewards } from './Rewards'; export const Pool = ({ pool, batchKey, batchIndex }: PoolProps) => { const { t } = useTranslation('library'); @@ -113,8 +114,15 @@ export const Pool = ({ pool, batchKey, batchIndex }: PoolProps) => { } }; + const displayJoin = + !isPoolSyncing && + state === 'Open' && + !membership && + !isReadOnlyAccount(activeAccount) && + activeAccount; + return ( - +
@@ -125,11 +133,6 @@ export const Pool = ({ pool, batchKey, batchIndex }: PoolProps) => { />
- {currentCommission > 0 && ( - - )} - -
-
- - {!isPoolSyncing && - state === 'Open' && - !membership && - !isReadOnlyAccount(activeAccount) && - activeAccount && ( - +
+
+ +
+
+ + {currentCommission > 0 && ( + + )} + + + + + {displayJoin && ( + )} +
diff --git a/src/library/Pool/types.ts b/src/library/Pool/types.ts index 6c463b447f..acaf7ae0b0 100644 --- a/src/library/Pool/types.ts +++ b/src/library/Pool/types.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-only import type { PoolAddresses, PoolRoles, PoolState } from 'contexts/Pools/types'; +import type { DisplayFor } from 'types'; export interface PoolProps { pool: Pool; @@ -17,3 +18,13 @@ export interface Pool { state: PoolState; roles: PoolRoles; } + +export interface RewardProps { + address: string; + displayFor?: DisplayFor; +} + +export interface RewardsGraphProps { + points: number[]; + syncing: boolean; +} diff --git a/src/locale/cn/library.json b/src/locale/cn/library.json index 025425559a..1da62b1e90 100644 --- a/src/locale/cn/library.json +++ b/src/locale/cn/library.json @@ -48,6 +48,7 @@ "dayAverage": "日平均值", "dayPerformance": "天内表现", "dayPerformanceStanding": "天内表现排名", + "dayPoolPerformance": "天内提名池表现", "destroying": "销毁中", "destroyingPools": "正在销毁提名池", "disclaimer": "免责声明", @@ -177,7 +178,7 @@ "validAddress": "有效地址", "validatingParachainBlocks": "验证平行链区块", "validatorCommission": "验证人佣金", - "validatorPerformance": "{{count}}天验证人性能", + "validatorPerformance": "{{count}}天内验证人表现", "valueTooSmall": "值太小", "viewDecentralization": "分布式指标", "viewMetrics": "验证人指标", diff --git a/src/locale/en/library.json b/src/locale/en/library.json index 5cd8212ba4..7e68eab8aa 100644 --- a/src/locale/en/library.json +++ b/src/locale/en/library.json @@ -48,6 +48,7 @@ "dayAverage": "Day Average", "dayPerformance": "Day Performance", "dayPerformanceStanding": "Day Performance Standing", + "dayPoolPerformance": "Day Pool Performance", "destroying": "Destroying", "destroyingPools": "Destroying Pools", "disclaimer": "Disclaimer", diff --git a/src/workers/poolPerformance.ts b/src/workers/poolPerformance.ts new file mode 100644 index 0000000000..ad4b46af4d --- /dev/null +++ b/src/workers/poolPerformance.ts @@ -0,0 +1,63 @@ +// Copyright 2023 @paritytech/polkadot-staking-dashboard authors & contributors +// SPDX-License-Identifier: GPL-3.0-only +/* eslint-disable no-await-in-loop */ + +import type { Exposure } from 'contexts/Staking/types'; +import type { ErasRewardPoints } from 'contexts/Validators/types'; +import type { AnyApi, AnyJson } from 'types'; + +// eslint-disable-next-line no-restricted-globals +export const ctx: Worker = self as any; + +// handle incoming message and route to correct handler. +ctx.addEventListener('message', async (event: AnyJson) => { + const { data } = event; + const { task } = data; + let message: AnyJson = {}; + switch (task) { + case 'processNominationPoolsRewardData': + message = await processErasStakersForNominationPoolRewards(data); + break; + default: + } + postMessage({ task, ...message }); +}); + +// Process `erasStakersClipped` and generate nomination pool reward data. +const processErasStakersForNominationPoolRewards = async ({ + bondedPools, + era, + erasRewardPoints, + exposures, +}: { + bondedPools: string[]; + era: string; + erasRewardPoints: ErasRewardPoints; + exposures: Exposure[]; +}) => { + const poolRewardData: Record> = {}; + + for (const address of bondedPools) { + let validator = null; + for (const exposure of exposures) { + const { others } = exposure.val; + const inOthers = others.find((o: AnyApi) => o.who === address); + + if (inOthers) { + validator = exposure.keys[1]; + break; + } + } + + if (validator) { + const rewardPoints: string = + erasRewardPoints[era]?.individual?.[validator || ''] ?? 0; + if (!poolRewardData[address]) poolRewardData[address] = {}; + poolRewardData[address][era] = rewardPoints; + } + } + + return { + poolRewardData, + }; +}; diff --git a/src/workers/stakers.ts b/src/workers/stakers.ts index 80beb59a5f..4353bae77b 100644 --- a/src/workers/stakers.ts +++ b/src/workers/stakers.ts @@ -202,5 +202,3 @@ const processExposures = (data: DataInitialiseExposures) => { who: activeAccount, }; }; - -export default null as any; diff --git a/yarn.lock b/yarn.lock index 711fd487e3..f83704f514 100644 --- a/yarn.lock +++ b/yarn.lock @@ -583,10 +583,15 @@ resolved "https://registry.yarnpkg.com/@polkadot-cloud/assets/-/assets-0.1.24.tgz#13b3ce04b63bda70a023e1fd71fa2998b739849b" integrity sha512-HLpZ7NIYhALceeAHx6gdQKmYKxdrkd2GVphiWvvhoDgPBF586OQu+lv9Prldfi11+mY0EAC0MjGdreelr1Ma8Q== -"@polkadot-cloud/core@^1.0.26": - version "1.0.26" - resolved "https://registry.yarnpkg.com/@polkadot-cloud/core/-/core-1.0.26.tgz#7c60cdf20a95b734d3d45d48efddd077112d0f71" - integrity sha512-0ZPL6f2WR0ezihBLLtVdCabYuTIz4NR2KFV8q+lsq3D2Qs8NQAytvqds4HBwsxq61oLdFc6lq11hDCe+lwy8gQ== +"@polkadot-cloud/core@^1.0.26", "@polkadot-cloud/core@^1.0.28": + version "1.0.28" + resolved "https://registry.yarnpkg.com/@polkadot-cloud/core/-/core-1.0.28.tgz#cb9351f27cb8c07b58433dcc9c00d4364a97028b" + integrity sha512-5MyZc5vIQDoNzRWYbRZ9EO1Xqtzu3GXFZjCaprCMZ2lxY6VmseXarnOMV1K20lR3mGU4wBFv6bKEmm09eMrpTw== + +"@polkadot-cloud/core@^1.0.29": + version "1.0.29" + resolved "https://registry.yarnpkg.com/@polkadot-cloud/core/-/core-1.0.29.tgz#c6b5a6c739872f5e814e47a193c9c5e829dedbcc" + integrity sha512-HhfowiWIcR1dLZu9KtMJMm6N1ySP2bkiq6aPaCepxn/gszn8tfpEZMw2X9EX++G2ZWM1zggQXs/05i6iPNaLeA== "@polkadot-cloud/react@^0.1.97": version "0.1.97" @@ -616,6 +621,15 @@ "@polkadot/util" "^12.5.1" bignumber.js "^9.1.1" +"@polkadot-cloud/utils@^0.0.23": + version "0.0.23" + resolved "https://registry.yarnpkg.com/@polkadot-cloud/utils/-/utils-0.0.23.tgz#eb703f74c7f05f763f7624727ba83589131ae1c5" + integrity sha512-IWqtn/cBgxletCH+MqBwZhxPxEbFLhfCU6L4RmCSCoes0bC1xUHMtFevPiJuaEkXQTdFvOnosA8BbSI01/GUuA== + dependencies: + "@polkadot/keyring" "^12.5.1" + "@polkadot/util" "^12.5.1" + bignumber.js "^9.1.1" + "@polkadot/api-augment@10.10.1": version "10.10.1" resolved "https://registry.yarnpkg.com/@polkadot/api-augment/-/api-augment-10.10.1.tgz#d3d296c923b0ff915c8d4f163e9b3bad70b89b9b" @@ -1296,16 +1310,16 @@ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.5.tgz#5cac7e7df3275bb95f79594f192d97da3b4fd5fe" integrity sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA== -"@typescript-eslint/eslint-plugin@^6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz#06abe4265e7c82f20ade2dcc0e3403c32d4f148b" - integrity sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw== +"@typescript-eslint/eslint-plugin@^6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz#fdb6f3821c0167e3356e9d89c80e8230b2e401f4" + integrity sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/type-utils" "6.8.0" - "@typescript-eslint/utils" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/type-utils" "6.9.0" + "@typescript-eslint/utils" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -1313,72 +1327,72 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.8.0.tgz#bb2a969d583db242f1ee64467542f8b05c2e28cb" - integrity sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg== +"@typescript-eslint/parser@^6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.9.0.tgz#2b402cadeadd3f211c25820e5433413347b27391" + integrity sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw== dependencies: - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/typescript-estree" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz#5cac7977385cde068ab30686889dd59879811efd" - integrity sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g== +"@typescript-eslint/scope-manager@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz#2626e9a7fe0e004c3e25f3b986c75f584431134e" + integrity sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" -"@typescript-eslint/type-utils@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz#50365e44918ca0fd159844b5d6ea96789731e11f" - integrity sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g== +"@typescript-eslint/type-utils@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz#23923c8c9677c2ad41457cf8e10a5f2946be1b04" + integrity sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ== dependencies: - "@typescript-eslint/typescript-estree" "6.8.0" - "@typescript-eslint/utils" "6.8.0" + "@typescript-eslint/typescript-estree" "6.9.0" + "@typescript-eslint/utils" "6.9.0" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.8.0.tgz#1ab5d4fe1d613e3f65f6684026ade6b94f7e3ded" - integrity sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ== +"@typescript-eslint/types@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.9.0.tgz#86a0cbe7ac46c0761429f928467ff3d92f841098" + integrity sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw== -"@typescript-eslint/typescript-estree@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz#9565f15e0cd12f55cf5aa0dfb130a6cb0d436ba1" - integrity sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg== +"@typescript-eslint/typescript-estree@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz#d0601b245be873d8fe49f3737f93f8662c8693d4" + integrity sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ== dependencies: - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/visitor-keys" "6.8.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.8.0.tgz#d42939c2074c6b59844d0982ce26a51d136c4029" - integrity sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q== +"@typescript-eslint/utils@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.9.0.tgz#5bdac8604fca4823f090e4268e681c84d3597c9f" + integrity sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.8.0" - "@typescript-eslint/types" "6.8.0" - "@typescript-eslint/typescript-estree" "6.8.0" + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/typescript-estree" "6.9.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.8.0": - version "6.8.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz#cffebed56ae99c45eba901c378a6447b06be58b8" - integrity sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg== +"@typescript-eslint/visitor-keys@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz#cc69421c10c4ac997ed34f453027245988164e80" + integrity sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg== dependencies: - "@typescript-eslint/types" "6.8.0" + "@typescript-eslint/types" "6.9.0" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -1533,7 +1547,7 @@ array-buffer-byte-length@^1.0.0: call-bind "^1.0.2" is-array-buffer "^3.0.1" -array-includes@^3.1.6: +array-includes@^3.1.6, array-includes@^3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== @@ -1561,7 +1575,7 @@ array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -array.prototype.findlastindex@^1.2.2: +array.prototype.findlastindex@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== @@ -1572,7 +1586,7 @@ array.prototype.findlastindex@^1.2.2: es-shim-unscopables "^1.0.0" get-intrinsic "^1.2.1" -array.prototype.flat@^1.3.1: +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== @@ -1582,7 +1596,7 @@ array.prototype.flat@^1.3.1: es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.3.1: +array.prototype.flatmap@^1.3.1, array.prototype.flatmap@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== @@ -2381,7 +2395,7 @@ eslint-config-prettier@^9.0.0: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f" integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== -eslint-import-resolver-node@^0.3.7: +eslint-import-resolver-node@^0.3.9: version "0.3.9" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== @@ -2410,26 +2424,26 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: dependencies: debug "^3.2.7" -eslint-plugin-import@^2.28.1: - version "2.28.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz#63b8b5b3c409bfc75ebaf8fb206b07ab435482c4" - integrity sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A== +eslint-plugin-import@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== dependencies: - array-includes "^3.1.6" - array.prototype.findlastindex "^1.2.2" - array.prototype.flat "^1.3.1" - array.prototype.flatmap "^1.3.1" + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.7" + eslint-import-resolver-node "^0.3.9" eslint-module-utils "^2.8.0" - has "^1.0.3" - is-core-module "^2.13.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.fromentries "^2.0.6" - object.groupby "^1.0.0" - object.values "^1.1.6" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" semver "^6.3.1" tsconfig-paths "^3.14.2" @@ -2455,10 +2469,10 @@ eslint-plugin-jsx-a11y@^6.7.1: object.fromentries "^2.0.6" semver "^6.3.0" -eslint-plugin-prefer-arrow-functions@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-arrow-functions/-/eslint-plugin-prefer-arrow-functions-3.1.4.tgz#a0761c7a0ba71461f6b2136fdf7f7cec1c82d778" - integrity sha512-LSO8VibqBKqzelr+L21mEIfachavCon+1SEumCJ6U8Ze2q0pntyojmomcVwd9RZBjrP+HV6k1Osz0B3Xwdq8WA== +eslint-plugin-prefer-arrow-functions@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-arrow-functions/-/eslint-plugin-prefer-arrow-functions-3.2.4.tgz#7bfbaab9646d1bb7cd7e29a58cfb796548c69508" + integrity sha512-HbPmlbO/iYQeVs2fuShNkGVJDfVfgSd84Vzxv+xlh+nIVoSsZvTj6yOqszw4mtG9JbiqMShVWqbVeoVsejE59w== eslint-plugin-prefer-arrow@^1.2.3: version "1.2.3" @@ -2802,7 +2816,7 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.1: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== @@ -3031,6 +3045,13 @@ hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -3169,12 +3190,12 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== +is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - has "^1.0.3" + hasown "^2.0.0" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" @@ -3774,7 +3795,7 @@ object.entries@^1.1.5, object.entries@^1.1.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.fromentries@^2.0.6: +object.fromentries@^2.0.6, object.fromentries@^2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== @@ -3783,7 +3804,7 @@ object.fromentries@^2.0.6: define-properties "^1.2.0" es-abstract "^1.22.1" -object.groupby@^1.0.0: +object.groupby@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== @@ -3801,7 +3822,7 @@ object.hasown@^1.1.2: define-properties "^1.2.0" es-abstract "^1.22.1" -object.values@^1.1.6: +object.values@^1.1.6, object.values@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==