From 3459a3f6a56bedc71bb55fe15295b0f599094d76 Mon Sep 17 00:00:00 2001 From: Yaroslav Grachev Date: Mon, 17 Feb 2025 15:20:36 +0300 Subject: [PATCH 1/2] feat: identity for delegation --- .../domains/identity/model/identity/model.ts | 10 ++--- .../identity/model/identity/service.ts | 38 ---------------- .../governance/aggregates/delegateRegistry.ts | 35 ++++++++++++++- .../features/governance/aggregates/voting.ts | 45 ++++++++++++++++++- .../components/Delegations/DelegateIcon.tsx | 26 ++++++----- .../components/Delegations/DelegateTitle.tsx | 18 ++++++-- .../components/CurrentDelegationModal.tsx | 25 ++++++----- .../components/DelegationList.tsx | 15 ++++--- 8 files changed, 134 insertions(+), 78 deletions(-) delete mode 100644 src/renderer/domains/identity/model/identity/service.ts diff --git a/src/renderer/domains/identity/model/identity/model.ts b/src/renderer/domains/identity/model/identity/model.ts index 43d198b9ed..1abebe4ddc 100644 --- a/src/renderer/domains/identity/model/identity/model.ts +++ b/src/renderer/domains/identity/model/identity/model.ts @@ -8,7 +8,6 @@ import { identityPallet } from '@/shared/pallet/identity'; import { type AccountId } from '@/shared/polkadotjs-schemas'; import { networkModel } from '@/entities/network'; -import { identityService } from './service'; import { type AccountIdentity } from './types'; type IdentityData = Record; @@ -79,14 +78,11 @@ const request = attach({ effect: requestIdentity, source: { apis: $apis, chains: $chains }, mapParams: ({ chainId, accounts }: RequestParams, { apis, chains }) => { - const identityChain = identityService.findIdentityChain(chains, chainId); - if (nullable(identityChain)) { - throw new Error(`Chain path from ${chainId} is broken, trace chain.parentId fields in config.`); - } + const identityChainId = chains[chainId]?.additional?.identityChain ?? chainId; - const api = apis[identityChain.chainId]; + const api = apis[identityChainId]; if (nullable(api)) { - throw new Error(`ApiPromise for chain ${identityChain.chainId} not found`); + throw new Error(`ApiPromise for chain ${identityChainId} not found`); } return { diff --git a/src/renderer/domains/identity/model/identity/service.ts b/src/renderer/domains/identity/model/identity/service.ts deleted file mode 100644 index 78730b1c36..0000000000 --- a/src/renderer/domains/identity/model/identity/service.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { type Chain, type ChainId } from '@/shared/core'; -import { nullable } from '@/shared/lib/utils'; - -const findIdentityChain = (chains: Record, initialChainId: ChainId) => { - let chainId = initialChainId; - let chain = chains[initialChainId]; - let identityChain: Chain | null = null; - - if (nullable(chain)) { - return null; - } - - while (nullable(identityChain)) { - if (chain.parentId) { - chainId = chain.parentId; - chain = chains[chainId]; - - if (nullable(chain)) { - break; - } - } else { - const identityChainId = chain.additional?.identityChain; - - if (nullable(identityChainId)) { - break; - } - - identityChain = chains[identityChainId] ?? null; - break; - } - } - - return identityChain; -}; - -export const identityService = { - findIdentityChain, -}; diff --git a/src/renderer/features/governance/aggregates/delegateRegistry.ts b/src/renderer/features/governance/aggregates/delegateRegistry.ts index e6f5cb282c..21817bfcd3 100644 --- a/src/renderer/features/governance/aggregates/delegateRegistry.ts +++ b/src/renderer/features/governance/aggregates/delegateRegistry.ts @@ -5,7 +5,9 @@ import { readonly } from 'patronum'; import { type DelegateAccount, delegationService } from '@/shared/api/governance'; import { type Chain } from '@/shared/core'; -import { MONTH, getBlockTimeAgo, nonNullable } from '@/shared/lib/utils'; +import { MONTH, getBlockTimeAgo, nonNullable, nullable, toAccountId } from '@/shared/lib/utils'; +import { type AccountId } from '@/shared/polkadotjs-schemas'; +import { identityDomain } from '@/domains/identity'; import { networkSelectorModel } from '../model/networkSelector'; const requestDelegateRegistry = createEvent(); @@ -63,6 +65,37 @@ sample({ target: $delegateRegistry, }); +sample({ + clock: $delegateRegistry, + source: { + chain: networkSelectorModel.$governanceChain, + identity: identityDomain.identity.$list, + }, + filter: ({ chain }, delegates) => { + if (nullable(chain)) return false; + + return delegates.some((delegate) => nullable(delegate.name)); + }, + fn: ({ chain, identity }, delegates) => { + const accounts = new Set(); + + for (const delegate of delegates) { + if (nonNullable(delegate.name)) continue; + + const accountId = toAccountId(delegate.address ?? delegate.accountId); + if (nonNullable(identity[chain!.chainId]?.[accountId])) continue; + + accounts.add(accountId); + } + + return { + chainId: chain!.chainId, + accounts: Array.from(accounts), + }; + }, + target: identityDomain.identity.request, +}); + export const delegateRegistryAggregate = { $delegateRegistry: readonly($delegateRegistry), $isRegistryLoading: requestDelegateRegistryFx.pending, diff --git a/src/renderer/features/governance/aggregates/voting.ts b/src/renderer/features/governance/aggregates/voting.ts index c5d213036c..c1d2b93bb7 100644 --- a/src/renderer/features/governance/aggregates/voting.ts +++ b/src/renderer/features/governance/aggregates/voting.ts @@ -1,8 +1,10 @@ import { combine, createEvent, sample } from 'effector'; import { type Address, type TrackId, type VotingMap } from '@/shared/core'; -import { nonNullable, nullable } from '@/shared/lib/utils'; -import { votingModel } from '@/entities/governance'; +import { nonNullable, nullable, toAccountId } from '@/shared/lib/utils'; +import { type AccountId } from '@/shared/polkadotjs-schemas'; +import { identityDomain } from '@/domains/identity'; +import { votingModel, votingService } from '@/entities/governance'; import { accountUtils, walletModel, walletUtils } from '@/entities/wallet'; import { networkSelectorModel } from '../model/networkSelector'; @@ -89,6 +91,45 @@ sample({ target: requestVoting, }); +sample({ + clock: $activeWalletVotes, + source: { + chain: networkSelectorModel.$governanceChain, + identity: identityDomain.identity.$list, + }, + filter: ({ chain }, activeVotes) => { + if (nullable(chain)) return false; + + for (const voteList of Object.values(activeVotes)) { + for (const vote of Object.values(voteList)) { + if (votingService.isDelegating(vote)) return true; + } + } + + return false; + }, + fn: ({ chain, identity }, activeVotes) => { + const accounts = new Set(); + + for (const voteList of Object.values(activeVotes)) { + for (const vote of Object.values(voteList)) { + if (!votingService.isDelegating(vote)) continue; + + const accountId = toAccountId(vote.target); + if (nonNullable(identity[chain!.chainId]?.[accountId])) continue; + + accounts.add(accountId); + } + } + + return { + chainId: chain!.chainId, + accounts: Array.from(accounts), + }; + }, + target: identityDomain.identity.request, +}); + export const votingAggregate = { $activeWalletVotes, $possibleAccountsForVoting, diff --git a/src/renderer/features/governance/components/Delegations/DelegateIcon.tsx b/src/renderer/features/governance/components/Delegations/DelegateIcon.tsx index 27f341d4cf..803639e5b8 100644 --- a/src/renderer/features/governance/components/Delegations/DelegateIcon.tsx +++ b/src/renderer/features/governance/components/Delegations/DelegateIcon.tsx @@ -13,18 +13,20 @@ export const DelegateIcon = ({ delegate, className }: Props) => { if (!delegate.name) return ; if (isDefaultImage(delegate.image)) { -
- {delegate.isOrganization ? ( - - ) : ( - - )} -
; + return ( +
+ {delegate.isOrganization ? ( + + ) : ( + + )} +
+ ); } return {delegate.name}; diff --git a/src/renderer/features/governance/components/Delegations/DelegateTitle.tsx b/src/renderer/features/governance/components/Delegations/DelegateTitle.tsx index cb029767d7..965d6f5fd7 100644 --- a/src/renderer/features/governance/components/Delegations/DelegateTitle.tsx +++ b/src/renderer/features/governance/components/Delegations/DelegateTitle.tsx @@ -1,9 +1,10 @@ -import { useUnit } from 'effector-react'; +import { useStoreMap, useUnit } from 'effector-react'; import { type DelegateAccount } from '@/shared/api/governance'; -import { cnTw, nullable } from '@/shared/lib/utils'; +import { cnTw, nullable, toAccountId } from '@/shared/lib/utils'; import { HeadlineText } from '@/shared/ui'; import { Account } from '@/shared/ui-entities'; +import { identityDomain } from '@/domains/identity'; import { networkSelectorModel } from '../../model/networkSelector'; type Props = { @@ -13,11 +14,22 @@ type Props = { export const DelegateTitle = ({ delegate, className }: Props) => { const chain = useUnit(networkSelectorModel.$governanceChain); + + const delegateName = useStoreMap({ + store: identityDomain.identity.$list, + keys: [chain?.chainId, delegate.accountId, delegate.address], + fn: (identity, [chainId, accountId, address]) => { + if (nullable(chainId)) return null; + + return delegate.name ?? identity[chainId]?.[toAccountId(address ?? accountId)]?.name ?? null; + }, + }); + if (nullable(chain) || nullable(delegate.accountId)) return null; return ( - + ); }; diff --git a/src/renderer/widgets/CurrentDelegationsModal/components/CurrentDelegationModal.tsx b/src/renderer/widgets/CurrentDelegationsModal/components/CurrentDelegationModal.tsx index d9e5dd7052..9c02c88fc6 100644 --- a/src/renderer/widgets/CurrentDelegationsModal/components/CurrentDelegationModal.tsx +++ b/src/renderer/widgets/CurrentDelegationsModal/components/CurrentDelegationModal.tsx @@ -1,6 +1,7 @@ import { useUnit } from 'effector-react'; import { useI18n } from '@/shared/i18n'; +import { toAccountId } from '@/shared/lib/utils'; import { Button, Loader } from '@/shared/ui'; import { Modal, SearchInput } from '@/shared/ui-kit'; import { OperationTitle } from '@/entities/chain'; @@ -45,16 +46,20 @@ export const CurrentDelegationModal = () => {
    - {delegationList.map((delegate) => ( - - ))} + {delegationList.map((delegate) => { + const accountId = toAccountId(delegate.address ?? delegate.accountId); + + return ( + + ); + })}
diff --git a/src/renderer/widgets/DelegationModal/components/DelegationList.tsx b/src/renderer/widgets/DelegationModal/components/DelegationList.tsx index cdaef5b6a5..5fa5765503 100644 --- a/src/renderer/widgets/DelegationModal/components/DelegationList.tsx +++ b/src/renderer/widgets/DelegationModal/components/DelegationList.tsx @@ -2,6 +2,7 @@ import { useUnit } from 'effector-react'; import { type DelegateAccount } from '@/shared/api/governance'; import { useI18n } from '@/shared/i18n'; +import { toAccountId } from '@/shared/lib/utils'; import { Button, Loader } from '@/shared/ui'; import { Box, SearchInput, Select } from '@/shared/ui-kit'; import { SortType } from '../common/constants'; @@ -68,11 +69,15 @@ export const DelegationList = ({ onClick, onAddCustomClick }: Props) => {
    - {delegationList.map((delegate) => ( - - ))} + {delegationList.map((delegate) => { + const accountId = toAccountId(delegate.address ?? delegate.accountId); + + return ( + + ); + })}
{delegationList.length === 0 && } From 2f123d3b05d4fc2e6c44e4113245c7542380080f Mon Sep 17 00:00:00 2001 From: Yaroslav Grachev Date: Mon, 17 Feb 2025 15:25:45 +0300 Subject: [PATCH 2/2] chore: simplify --- .../governance/aggregates/delegateRegistry.ts | 8 ++------ .../features/governance/aggregates/voting.ts | 12 +----------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/renderer/features/governance/aggregates/delegateRegistry.ts b/src/renderer/features/governance/aggregates/delegateRegistry.ts index 21817bfcd3..a0f165515d 100644 --- a/src/renderer/features/governance/aggregates/delegateRegistry.ts +++ b/src/renderer/features/governance/aggregates/delegateRegistry.ts @@ -5,7 +5,7 @@ import { readonly } from 'patronum'; import { type DelegateAccount, delegationService } from '@/shared/api/governance'; import { type Chain } from '@/shared/core'; -import { MONTH, getBlockTimeAgo, nonNullable, nullable, toAccountId } from '@/shared/lib/utils'; +import { MONTH, getBlockTimeAgo, nonNullable, toAccountId } from '@/shared/lib/utils'; import { type AccountId } from '@/shared/polkadotjs-schemas'; import { identityDomain } from '@/domains/identity'; import { networkSelectorModel } from '../model/networkSelector'; @@ -71,11 +71,7 @@ sample({ chain: networkSelectorModel.$governanceChain, identity: identityDomain.identity.$list, }, - filter: ({ chain }, delegates) => { - if (nullable(chain)) return false; - - return delegates.some((delegate) => nullable(delegate.name)); - }, + filter: ({ chain }) => nonNullable(chain), fn: ({ chain, identity }, delegates) => { const accounts = new Set(); diff --git a/src/renderer/features/governance/aggregates/voting.ts b/src/renderer/features/governance/aggregates/voting.ts index c1d2b93bb7..cb13767dbc 100644 --- a/src/renderer/features/governance/aggregates/voting.ts +++ b/src/renderer/features/governance/aggregates/voting.ts @@ -97,17 +97,7 @@ sample({ chain: networkSelectorModel.$governanceChain, identity: identityDomain.identity.$list, }, - filter: ({ chain }, activeVotes) => { - if (nullable(chain)) return false; - - for (const voteList of Object.values(activeVotes)) { - for (const vote of Object.values(voteList)) { - if (votingService.isDelegating(vote)) return true; - } - } - - return false; - }, + filter: ({ chain }) => nonNullable(chain), fn: ({ chain, identity }, activeVotes) => { const accounts = new Set();