Skip to content

Commit

Permalink
feat: Activate People Chain and re-enable identities (#2198)
Browse files Browse the repository at this point in the history
  • Loading branch information
rossbulat authored Aug 1, 2024
1 parent c4fada1 commit 2a6a624
Show file tree
Hide file tree
Showing 17 changed files with 263 additions and 124 deletions.
44 changes: 40 additions & 4 deletions src/config/networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import WestendInlineSVG from 'img/westend_inline.svg?react';
import PolkadotTokenSVG from 'config/tokens/svg/DOT.svg?react';
import KusamaTokenSVG from 'config/tokens/svg/KSM.svg?react';
import WestendTokenSVG from 'config/tokens/svg/WND.svg?react';
import type { Networks } from 'types';
import type { Networks, SystemChain } from 'types';
import BigNumber from 'bignumber.js';

export const NetworkList: Networks = {
Expand All @@ -30,7 +30,6 @@ export const NetworkList: Networks = {
Stakeworld: 'wss://dot-rpc.stakeworld.io',
},
},
namespace: '91b171bb158e2d3848fa23a9f1c25182',
colors: {
primary: {
light: 'rgb(211, 48, 121)',
Expand Down Expand Up @@ -87,7 +86,6 @@ export const NetworkList: Networks = {
Stakeworld: 'wss://ksm-rpc.stakeworld.io',
},
},
namespace: 'b0a8d493285c2df73290dfb7e61f870f',
colors: {
primary: {
light: 'rgb(31, 41, 55)',
Expand Down Expand Up @@ -143,7 +141,6 @@ export const NetworkList: Networks = {
Stakeworld: 'wss://wnd-rpc.stakeworld.io',
},
},
namespace: 'e143f23803ac50e8f6f8e62695d1ce9e',
colors: {
primary: {
light: '#da4e71',
Expand Down Expand Up @@ -185,3 +182,42 @@ export const NetworkList: Networks = {
maxExposurePageSize: new BigNumber(64),
},
};

export const SystemChainList: Record<string, SystemChain> = {
'people-polkadot': {
name: 'people-polkadot',
ss58: 0,
units: 10,
unit: 'DOT',
endpoints: {
lightClient: 'people_polkadot', // NOTE: Currently not being used. TODO: Revise this and activate once People chain specs are available to use.
rpcEndpoints: {
Parity: 'wss://polkadot-people-rpc.polkadot.io',
},
},
},
'people-kusama': {
name: 'people-kusama',
ss58: 2,
units: 12,
unit: 'KSM',
endpoints: {
lightClient: 'people_kusama', // NOTE: Currently not being used. TODO: Revise this and activate once People chain specs are available to use.
rpcEndpoints: {
Parity: 'wss://kusama-people-rpc.polkadot.io',
},
},
},
'people-westend': {
name: 'people-westend',
ss58: 42,
units: 12,
unit: 'WND',
endpoints: {
lightClient: 'people_westend', // NOTE: Currently not being used. TODO: Revise this and activate once People chain specs are available to use.
rpcEndpoints: {
Parity: 'wss://westend-people-rpc.polkadot.io',
},
},
},
};
5 changes: 0 additions & 5 deletions src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,3 @@ export const MaxPayoutDays = 60;
export const MaxEraRewardPointsEras = 10;
export const ZondaxMetadataHashApiUrl =
'https://api.zondax.ch/polkadot/node/metadata/hash';

/*
* People Chain migration - disallow identities on networks where People Chain is live.
*/
export const PeopleChainNetworks = ['polkadot', 'westend', 'kusama'];
2 changes: 2 additions & 0 deletions src/contexts/Api/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ export const defaultStakingMetrics: APIStakingMetrics = {

export const defaultApiContext: APIContextInterface = {
api: null,
peopleApi: null,
chainState: defaultChainState,
isReady: false,
apiStatus: 'disconnected',
peopleApiStatus: 'disconnected',
connectionType: 'ws',
setConnectionType: (connectionType) => {},
rpcEndpoint: '',
Expand Down
131 changes: 91 additions & 40 deletions src/contexts/Api/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ import { useEventListener } from 'usehooks-ts';
import BigNumber from 'bignumber.js';
import { SyncController } from 'controllers/Sync';
import { ApiController } from 'controllers/Api';
import type { ApiStatus, ConnectionType } from 'model/Api/types';
import type {
APIEventDetail,
ApiStatus,
ConnectionType,
} from 'model/Api/types';
import { StakingConstants } from 'model/Query/StakingConstants';
import { Era } from 'model/Query/Era';
import { NetworkMeta } from 'model/Query/NetworkMeta';
Expand All @@ -48,6 +52,10 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// Store Api connection status for the current network.
const [apiStatus, setApiStatus] = useState<ApiStatus>('disconnected');

// Store Api connection status for People system chain.
const [peopleApiStatus, setPeopleApiStatus] =
useState<ApiStatus>('disconnected');

// Store whether light client is active.
const [connectionType, setConnectionTypeState] = useState<ConnectionType>(
localStorage.getItem('light_client') ? 'sc' : 'ws'
Expand Down Expand Up @@ -184,7 +192,8 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// API is now ready to be used.
setApiStatus('ready');

// Set `initialization` syncing to complete.
// Set `initialization` syncing to complete. NOTE: This synchonisation is only considering the
// relay chain sync state, and not system/para chains.
SyncController.dispatch('initialization', 'complete');

// 3. Initialise subscriptions:
Expand Down Expand Up @@ -215,52 +224,92 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
SubscriptionsController.set(network, 'activeEra', new ActiveEra(network));
};

// Handle Api disconnection.
const onApiDisconnected = () => {
setApiStatus('disconnected');
};

// Handle `polkadot-api` events.
const handleNewApiStatus = (e: Event) => {
if (isCustomEvent(e)) {
const {
status,
network: eventNetwork,
type,
rpcEndpoint: eventRpcEndpoints,
} = e.detail;

// UI is only interested in events for the current network.
if (
eventNetwork !== network ||
connectionTypeRef.current !== type ||
rpcEndpointRef.current !== eventRpcEndpoints
) {
return;
}
const { chainType } = e.detail;

switch (status) {
case 'ready':
onApiReady();
break;
case 'connecting':
setApiStatus('connecting');
break;
case 'connected':
setApiStatus('connected');
break;
case 'disconnected':
onApiDisconnected();
break;
case 'error':
// Reinitialise api on error. We can confidently do this with well-known RPC providers,
// but not with custom endpoints.
reInitialiseApi(connectionType);
break;
if (chainType === 'relay') {
handleRelayApiStatus(e.detail);
} else if (chainType === 'system') {
handleSystemApiStatus(e.detail);
}
}
};

// Handle an Api status event for a relay chain.
const handleRelayApiStatus = (detail: APIEventDetail) => {
const {
status,
network: eventNetwork,
connectionType: eventConnectionType,
rpcEndpoint: eventRpcEndpoint,
} = detail;

// UI is only interested in events for the current network.
if (
eventNetwork !== network ||
connectionTypeRef.current !== eventConnectionType ||
rpcEndpointRef.current !== eventRpcEndpoint
) {
return;
}
switch (status) {
case 'ready':
onApiReady();
break;
case 'connecting':
setApiStatus('connecting');
break;
case 'connected':
setApiStatus('connected');
break;
case 'disconnected':
setApiStatus('disconnected');
break;
case 'error':
// Reinitialise api on error. We can confidently do this with well-known RPC providers,
// but not with custom endpoints.
reInitialiseApi(eventConnectionType);
break;
}
};

// Handle an Api status event for a system chain. NOTE: Only People chain is currently being used.
const handleSystemApiStatus = (detail: APIEventDetail) => {
const {
status,
network: eventNetwork,
connectionType: eventConnectionType,
} = detail;

// UI is only interested in events for the People system chain.
if (
eventNetwork !== `people-${network}` ||
connectionTypeRef.current !== eventConnectionType
/* || rpcEndpointRef.current !== eventRpcEndpoint // NOTE: Only `Parity` being used currently. */
) {
return;
}
switch (status) {
case 'ready':
setPeopleApiStatus('ready');
break;
case 'connecting':
setPeopleApiStatus('connecting');
break;
case 'connected':
setPeopleApiStatus('connected');
break;
case 'disconnected':
setPeopleApiStatus('disconnected');
break;
case 'error':
// Silently fail.
break;
}
};

// Handle new network metrics updates.
const handleNetworkMetricsUpdate = (e: Event): void => {
if (isCustomEvent(e)) {
Expand Down Expand Up @@ -434,8 +483,10 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
<APIContext.Provider
value={{
api: ApiController.get(network)?.api || null,
peopleApi: ApiController.get(`people-${network}`)?.api || null,
chainState,
apiStatus,
peopleApiStatus,
connectionType,
setConnectionType,
rpcEndpoint,
Expand Down
2 changes: 2 additions & 0 deletions src/contexts/Api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ export interface APIStakingMetrics {

export interface APIContextInterface {
api: ApiPromise | null;
peopleApi: ApiPromise | null;
chainState: APIChainState;
isReady: boolean;
apiStatus: ApiStatus;
peopleApiStatus: ApiStatus;
connectionType: ConnectionType;
setConnectionType: (connectionType: ConnectionType) => void;
rpcEndpoint: string;
Expand Down
6 changes: 4 additions & 2 deletions src/contexts/Balances/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const BalancesContext = createContext<BalancesContextInterface>(
export const useBalances = () => useContext(BalancesContext);

export const BalancesProvider = ({ children }: { children: ReactNode }) => {
const { api } = useApi();
const { api, peopleApi } = useApi();
const { getBondedAccount } = useBonded();
const { accounts } = useImportedAccounts();
const createPoolAccounts = useCreatePoolAccounts();
Expand Down Expand Up @@ -67,7 +67,9 @@ export const BalancesProvider = ({ children }: { children: ReactNode }) => {
id: String(poolId),
addresses: { ...createPoolAccounts(Number(poolId)) },
});
ActivePoolsController.syncPools(api, address, newPools);
if (peopleApi) {
ActivePoolsController.syncPools(api, peopleApi, address, newPools);
}
}
}
};
Expand Down
11 changes: 9 additions & 2 deletions src/contexts/Pools/ActivePool/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const useActivePool = () => useContext(ActivePoolContext);

export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
const { isReady, api } = useApi();
const { getPoolMembership } = useBalances();
const { isReady, api, peopleApi } = useApi();
const { activeAccount } = useActiveAccounts();
const createPoolAccounts = useCreatePoolAccounts();
const { getAccountPoolRoles, bondedPools } = useBondedPools();
Expand Down Expand Up @@ -99,7 +99,14 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
}));

SyncController.dispatch('active-pools', 'syncing');
ActivePoolsController.syncPools(api, activeAccount, newActivePools);
if (peopleApi) {
ActivePoolsController.syncPools(
api,
peopleApi,
activeAccount,
newActivePools
);
}
} else {
// No active pools to sync. Mark as complete.
SyncController.dispatch('active-pools', 'complete');
Expand Down
8 changes: 4 additions & 4 deletions src/contexts/Validators/ValidatorEntries/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { AnyApi, Fn } from 'types';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import { useNetwork } from 'contexts/Network';
import { useApi } from 'contexts/Api';
import { MaxEraRewardPointsEras, PeopleChainNetworks } from 'consts';
import { MaxEraRewardPointsEras } from 'consts';
import { useStaking } from 'contexts/Staking';
import type {
EraPointsBoundaries,
Expand Down Expand Up @@ -45,6 +45,7 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
const {
isReady,
api,
peopleApi,
consts: { historyDepth },
networkMetrics: { earliestStoredSession },
} = useApi();
Expand Down Expand Up @@ -316,11 +317,10 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// NOTE: validators are shuffled before committed to state.
setValidators(shuffle(validatorEntries));

// PEOPLE CHAIN MIGRATION: Currently ignoring identities while People Chain is not supported.
if (!PeopleChainNetworks.includes(network)) {
if (peopleApi) {
const addresses = validatorEntries.map(({ address }) => address);
const { identities, supers } = await IdentitiesController.fetch(
api,
peopleApi,
addresses
);
setValidatorIdentities(identities);
Expand Down
Loading

0 comments on commit 2a6a624

Please sign in to comment.