From eb72b16b9d2b9ed0a255254316275eacfb1f4424 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 14 Nov 2024 19:01:27 +0700
Subject: [PATCH 01/84] init papi ws / sm, get chainSpec
---
packages/app/package.json | 1 +
packages/app/src/config/networks.ts | 24 +-
packages/app/src/config/util.ts | 45 +
packages/app/src/contexts/Api/defaults.ts | 10 +
packages/app/src/contexts/Api/index.tsx | 31 +-
packages/app/src/contexts/Api/types.ts | 6 +-
packages/app/src/model/Api/index.ts | 123 +-
packages/app/src/model/Api/types.ts | 11 +
packages/app/src/types.ts | 10 +-
yarn.lock | 1281 ++++++++++++++++++++-
10 files changed, 1482 insertions(+), 60 deletions(-)
create mode 100644 packages/app/src/config/util.ts
diff --git a/packages/app/package.json b/packages/app/package.json
index 996f9f99a..c4b9eae02 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -52,6 +52,7 @@
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"plugin-staking-api": "workspace:*",
+ "polkadot-api": "^1.7.3",
"qrcode-generator": "1.4.4",
"rc-slider": "^11.1.6",
"react": "^18.3.1",
diff --git a/packages/app/src/config/networks.ts b/packages/app/src/config/networks.ts
index 116bafd56..1a2b16a83 100644
--- a/packages/app/src/config/networks.ts
+++ b/packages/app/src/config/networks.ts
@@ -17,7 +17,8 @@ export const NetworkList: Networks = {
polkadot: {
name: 'polkadot',
endpoints: {
- lightClient: 'polkadot',
+ lightClientKey: 'polkadot',
+ lightClient: async () => await import('polkadot-api/chains/polkadot'),
defaultRpcEndpoint: 'Automata 1RPC',
rpcEndpoints: {
'Automata 1RPC': 'wss://1rpc.io/dot',
@@ -72,7 +73,8 @@ export const NetworkList: Networks = {
kusama: {
name: 'kusama',
endpoints: {
- lightClient: 'ksmcc3',
+ lightClientKey: 'ksmcc3',
+ lightClient: async () => await import('polkadot-api/chains/ksmcc3'),
defaultRpcEndpoint: 'Automata 1RPC',
rpcEndpoints: {
'Automata 1RPC': 'wss://1rpc.io/ksm',
@@ -127,7 +129,8 @@ export const NetworkList: Networks = {
westend: {
name: 'westend',
endpoints: {
- lightClient: 'westend2',
+ lightClientKey: 'westend2',
+ lightClient: async () => await import('polkadot-api/chains/westend2'),
defaultRpcEndpoint: 'Automata 1RPC',
rpcEndpoints: {
Dwellir: 'wss://westend-rpc.dwellir.com',
@@ -187,11 +190,14 @@ export const SystemChainList: Record = {
units: 10,
unit: 'DOT',
endpoints: {
- lightClient: 'polkadot_people',
+ lightClientKey: 'polkadot_people',
+ lightClient: async () =>
+ await import('polkadot-api/chains/polkadot_people'),
rpcEndpoints: {
Parity: 'wss://polkadot-people-rpc.polkadot.io',
},
},
+ relayChain: 'polkadot',
},
'people-kusama': {
name: 'people-kusama',
@@ -199,11 +205,14 @@ export const SystemChainList: Record = {
units: 12,
unit: 'KSM',
endpoints: {
- lightClient: 'kusama_people',
+ lightClientKey: 'ksmcc3_people',
+ lightClient: async () =>
+ await import('polkadot-api/chains/ksmcc3_people'),
rpcEndpoints: {
Parity: 'wss://kusama-people-rpc.polkadot.io',
},
},
+ relayChain: 'kusama',
},
'people-westend': {
name: 'people-westend',
@@ -211,10 +220,13 @@ export const SystemChainList: Record = {
units: 12,
unit: 'WND',
endpoints: {
- lightClient: 'westend_people',
+ lightClientKey: 'westend2_people',
+ lightClient: async () =>
+ await import('polkadot-api/chains/westend2_people'),
rpcEndpoints: {
Parity: 'wss://westend-people-rpc.polkadot.io',
},
},
+ relayChain: 'westend',
},
};
diff --git a/packages/app/src/config/util.ts b/packages/app/src/config/util.ts
new file mode 100644
index 000000000..60d869153
--- /dev/null
+++ b/packages/app/src/config/util.ts
@@ -0,0 +1,45 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { ApiChainType } from 'model/Api/types';
+import type { AnyApi, NetworkName, SystemChainId } from 'types';
+import { NetworkList, SystemChainList } from './networks';
+
+// Get the light client metadata for the given chain type and network.
+export const getLightClientMetadata = (
+ chainType: ApiChainType,
+ network: NetworkName | SystemChainId
+): {
+ chain: {
+ key: string;
+ fn: () => Promise;
+ };
+ relay?: {
+ key: string;
+ fn: () => Promise;
+ };
+} => {
+ if (chainType === 'relay') {
+ return {
+ chain: {
+ key: NetworkList[network].endpoints.lightClientKey,
+ fn: NetworkList[network].endpoints.lightClient,
+ },
+ };
+ }
+
+ const { relayChain } = SystemChainList[network];
+ const relay = NetworkList[relayChain];
+ const system = SystemChainList[network];
+
+ return {
+ relay: {
+ key: relay.endpoints.lightClientKey,
+ fn: relay.endpoints.lightClient,
+ },
+ chain: {
+ key: system.endpoints.lightClientKey,
+ fn: system.endpoints.lightClient,
+ },
+ };
+};
diff --git a/packages/app/src/contexts/Api/defaults.ts b/packages/app/src/contexts/Api/defaults.ts
index 09b5857f2..8d647590e 100644
--- a/packages/app/src/contexts/Api/defaults.ts
+++ b/packages/app/src/contexts/Api/defaults.ts
@@ -12,6 +12,7 @@ import type {
APINetworkMetrics,
APIPoolsConfig,
APIStakingMetrics,
+ PapiChainSpecContext,
} from 'contexts/Api/types';
export const defaultChainState: APIChainState = {
@@ -43,6 +44,14 @@ export const defaultNetworkMetrics: APINetworkMetrics = {
minimumActiveStake: new BigNumber(0),
};
+export const defaultChainSpecs: PapiChainSpecContext = {
+ genesisHash: '',
+ ss58Format: 0,
+ tokenDecimals: 0,
+ tokenSymbol: '',
+ received: false,
+};
+
export const defaultActiveEra: APIActiveEra = {
index: new BigNumber(0),
start: new BigNumber(0),
@@ -77,6 +86,7 @@ export const defaultApiContext: APIContextInterface = {
api: null,
peopleApi: null,
chainState: defaultChainState,
+ chainSpecs: defaultChainSpecs,
isReady: false,
apiStatus: 'disconnected',
peopleApiStatus: 'disconnected',
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 955615b7d..8ffa019c9 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -14,6 +14,7 @@ import type {
APIPoolsConfig,
APIProviderProps,
APIStakingMetrics,
+ PapiChainSpecContext,
} from './types';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import {
@@ -24,6 +25,7 @@ import {
defaultPoolsConfig,
defaultNetworkMetrics,
defaultStakingMetrics,
+ defaultChainSpecs,
} from './defaults';
import { isCustomEvent } from 'controllers/utils';
import { useEventListener } from 'usehooks-ts';
@@ -133,6 +135,10 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
);
const stakingMetricsRef = useRef(stakingMetrics);
+ // Store chain specs from PAPI.
+ const [chainSpecs, setChainSpecs] =
+ useState(defaultChainSpecs);
+
// Fetch chain state. Called once `provider` has been initialised.
const onApiReady = async () => {
const { api } = ApiController.get(network);
@@ -220,6 +226,26 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
SubscriptionsController.set(network, 'activeEra', new ActiveEra(network));
};
+ const handlePapiReady = (e: Event) => {
+ if (isCustomEvent(e)) {
+ const { chainType, genesisHash, ss58Format, tokenDecimals, tokenSymbol } =
+ e.detail;
+
+ if (chainType === 'relay') {
+ const newChainSpecs: PapiChainSpecContext = {
+ genesisHash,
+ ss58Format,
+ tokenDecimals,
+ tokenSymbol,
+ received: true,
+ };
+ setChainSpecs({ ...newChainSpecs, received: true });
+
+ // TODO: set consts from here.
+ }
+ }
+ };
+
// Handle `polkadot-api` events.
const handleNewApiStatus = (e: Event) => {
if (isCustomEvent(e)) {
@@ -434,6 +460,7 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
setRpcEndpoint(initialRpcEndpoint());
// Reset consts and chain state.
+ setChainSpecs(defaultChainSpecs);
setConsts(defaultConsts);
setChainState(defaultChainState);
setStateWithRef(
@@ -464,6 +491,7 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// Add event listener for api events and subscription updates.
const documentRef = useRef(document);
useEventListener('api-status', handleNewApiStatus, documentRef);
+ useEventListener('papi-ready', handlePapiReady, documentRef);
useEventListener(
'new-network-metrics',
handleNetworkMetricsUpdate,
@@ -483,13 +511,14 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
api: ApiController.get(network)?.api || null,
peopleApi: ApiController.get(`people-${network}`)?.api || null,
chainState,
+ chainSpecs,
apiStatus,
peopleApiStatus,
connectionType,
setConnectionType,
rpcEndpoint,
setRpcEndpoint,
- isReady: apiStatus === 'ready',
+ isReady: apiStatus === 'ready' && chainSpecs.received === true,
consts,
networkMetrics,
activeEra,
diff --git a/packages/app/src/contexts/Api/types.ts b/packages/app/src/contexts/Api/types.ts
index ac7615cd8..0420ed7f8 100644
--- a/packages/app/src/contexts/Api/types.ts
+++ b/packages/app/src/contexts/Api/types.ts
@@ -5,7 +5,7 @@ import type { ApiPromise } from '@polkadot/api';
import type BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import type { NetworkName } from '../../types';
-import type { ApiStatus, ConnectionType } from 'model/Api/types';
+import type { ApiStatus, ConnectionType, PapiChainSpec } from 'model/Api/types';
import type { AnyJson } from '@w3ux/types';
export interface APIProviderProps {
@@ -40,6 +40,9 @@ export interface APINetworkMetrics {
minimumActiveStake: BigNumber;
}
+export type PapiChainSpecContext = PapiChainSpec & {
+ received: boolean;
+};
export interface APIActiveEra {
index: BigNumber;
start: BigNumber;
@@ -74,6 +77,7 @@ export interface APIContextInterface {
api: ApiPromise | null;
peopleApi: ApiPromise | null;
chainState: APIChainState;
+ chainSpecs: PapiChainSpecContext;
isReady: boolean;
apiStatus: ApiStatus;
peopleApiStatus: ApiStatus;
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index f6c1374a1..e4dee3a01 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -9,17 +9,22 @@ import type {
APIEventDetail,
ConnectionType,
EventApiStatus,
+ PapiChainSpec,
+ PapiReadyEvent,
} from './types';
import { SubscriptionsController } from 'controllers/Subscriptions';
import { ScProvider } from '@polkadot/rpc-provider/substrate-connect';
import { WellKnownChain } from '@substrate/connect';
import * as Sc from '@substrate/connect';
+import type { PolkadotClient } from 'polkadot-api';
+import { createClient } from 'polkadot-api';
+import { getWsProvider } from 'polkadot-api/ws-provider/web';
+import { getSmProvider } from 'polkadot-api/sm-provider';
+import { startFromWorker } from 'polkadot-api/smoldot/from-worker';
+import SmWorker from 'polkadot-api/smoldot/worker?worker';
+import { getLightClientMetadata } from 'config/util';
export class Api {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// The network name associated with this Api instance.
network: NetworkName | SystemChainId;
@@ -29,6 +34,12 @@ export class Api {
// API provider.
#provider: WsProvider | ScProvider;
+ // PAPI Instance.
+ #papiClient: PolkadotClient;
+
+ // PAPI Chain Spec.
+ #papiChainSpec: PapiChainSpec;
+
// API instance.
#api: ApiPromise;
@@ -38,31 +49,27 @@ export class Api {
// The current connection type.
#connectionType: ConnectionType;
- // ------------------------------------------------------
- // Getters.
- // ------------------------------------------------------
-
get api() {
return this.#api;
}
+ get papiClient() {
+ return this.#papiClient;
+ }
+
+ get papiChainSpec() {
+ return this.#papiChainSpec;
+ }
+
get connectionType() {
return this.#connectionType;
}
- // ------------------------------------------------------
- // Constructor.
- // ------------------------------------------------------
-
constructor(network: NetworkName | SystemChainId, chainType: ApiChainType) {
this.network = network;
this.#chainType = chainType;
}
- // ------------------------------------------------------
- // Initialization.
- // ------------------------------------------------------
-
// Class initialization. Sets the `provider` and `api` class members.
async initialize(type: ConnectionType, rpcEndpoint: string) {
// Set connection metadata.
@@ -86,14 +93,19 @@ export class Api {
// Tell UI api is connecting.
this.dispatchEvent(this.ensureEventStatus('connecting'));
- // Initialise api.
+ // Initialise Polkadot JS API.
this.#api = new ApiPromise({ provider: this.#provider });
- // Initialise api events.
+ // NOTE: Unlike Polkadot JS API, Papi client does not have an asynchronous initialization
+ // stage that leads to `isReady`. If using papi client, we can immediately attempt to fetch
+ // the chainSpec via the client.∑
this.initApiEvents();
// Wait for api to be ready.
await this.#api.isReady;
+
+ // Fetch chain spec and metadata from PAPI client.
+ await this.fetchChainSpec();
} catch (e) {
// TODO: report a custom api status error that can flag to the UI the rpcEndpoint failed -
// retry or select another one. Useful for custom endpoint configs.
@@ -101,10 +113,6 @@ export class Api {
}
}
- // ------------------------------------------------------
- // Provider initialization.
- // ------------------------------------------------------
-
// Initiate Websocket Provider.
initWsProvider() {
const endpoint =
@@ -114,7 +122,11 @@ export class Api {
this.#rpcEndpoint
];
+ // Initialize Polkadot JS Provider.
this.#provider = new WsProvider(endpoint);
+
+ // Initialize PAPI Client.
+ this.#papiClient = createClient(getWsProvider(endpoint));
}
// Dynamically load and connect to Substrate Connect.
@@ -122,20 +134,67 @@ export class Api {
// Get light client key from network list.
const lightClientKey =
this.#chainType === 'relay'
- ? NetworkList[this.network].endpoints.lightClient
- : SystemChainList[this.network].endpoints.lightClient;
+ ? NetworkList[this.network].endpoints.lightClientKey
+ : SystemChainList[this.network].endpoints.lightClientKey;
// Instantiate light client provider.
this.#provider = new ScProvider(
Sc as AnyApi,
WellKnownChain[lightClientKey as keyof typeof WellKnownChain]
);
+
+ // Initialise PAPI light client.
+ const smoldot = startFromWorker(new SmWorker());
+ const smMetadata = getLightClientMetadata(this.#chainType, this.network);
+
+ const chain = getSmProvider(
+ smoldot.addChain({
+ chainSpec: await smMetadata.chain.fn(),
+ potentialRelayChains: smMetadata?.relay
+ ? [await smoldot.addChain({ chainSpec: await smMetadata.relay.fn() })]
+ : undefined,
+ })
+ );
+ this.#papiClient = createClient(chain);
+
+ // Connect to Polkadot JS API provider.
await this.#provider.connect();
}
- // ------------------------------------------------------
- // Event handling.
- // ------------------------------------------------------
+ async fetchChainSpec() {
+ try {
+ const chainSpecData = await this.#papiClient.getChainSpecData();
+
+ const { genesisHash, properties } = chainSpecData;
+ const { ss58Format, tokenDecimals, tokenSymbol } = properties;
+
+ this.#papiChainSpec = {
+ genesisHash,
+ ss58Format,
+ tokenDecimals,
+ tokenSymbol,
+ };
+
+ // Dispatch 'papi-ready' event to let contexts populate constants.
+ this.dispatchPapiReadyEvent();
+ } catch (e) {
+ console.debug('PAPI chain spec failed');
+ // TODO: Expand this when PJS API has been removed. Flag an error if there are any issues
+ // bootstrapping chain spec. NOTE: This can happen when PAPI is the standalone connection
+ // method.
+ //this.dispatchEvent(this.ensureEventStatus('error'), { err: 'ChainSpecError' });
+ }
+ }
+
+ // Handler for dispatching `papi-ready` events.
+ dispatchPapiReadyEvent() {
+ const detail: PapiReadyEvent = {
+ network: this.network,
+ chainType: this.#chainType,
+ ...this.#papiChainSpec,
+ };
+ document.dispatchEvent(new CustomEvent('papi-ready', { detail }));
+ }
// Set up API event listeners. Sends information to the UI.
async initApiEvents() {
@@ -156,7 +215,7 @@ export class Api {
});
}
- // Handler for dispatching events.
+ // Handler for dispatching `api-status` events.
dispatchEvent(
status: EventApiStatus,
options?: {
@@ -176,10 +235,6 @@ export class Api {
document.dispatchEvent(new CustomEvent('api-status', { detail }));
}
- // ------------------------------------------------------
- // Class helpers.
- // ------------------------------------------------------
-
// Ensures the provided status is a valid `EventStatus` being passed, or falls back to `error`.
ensureEventStatus = (status: string | EventApiStatus): EventApiStatus => {
const eventStatus: string[] = [
@@ -207,10 +262,6 @@ export class Api {
}
};
- // ------------------------------------------------------
- // Disconnect.
- // ------------------------------------------------------
-
// Disconnect gracefully from API and provider.
async disconnect(destroy = false) {
this.unsubscribe();
diff --git a/packages/app/src/model/Api/types.ts b/packages/app/src/model/Api/types.ts
index 5129cb463..eebef4ff4 100644
--- a/packages/app/src/model/Api/types.ts
+++ b/packages/app/src/model/Api/types.ts
@@ -17,6 +17,17 @@ export interface APIEventDetail {
err?: string;
}
+export interface PapiChainSpec {
+ genesisHash: string;
+ ss58Format: number;
+ tokenDecimals: number;
+ tokenSymbol: string;
+}
+export type PapiReadyEvent = PapiChainSpec & {
+ network: NetworkName | SystemChainId;
+ chainType: string;
+};
+
export type ConnectionType = 'ws' | 'sc';
export type ApiStatus = 'connecting' | 'connected' | 'disconnected' | 'ready';
diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts
index 0a3b87cd4..e909ff810 100644
--- a/packages/app/src/types.ts
+++ b/packages/app/src/types.ts
@@ -16,7 +16,7 @@ import type {
} from 'contexts/Api/types';
import type { SyncEvent } from 'controllers/Sync/types';
import type { DetailActivePool } from 'controllers/ActivePools/types';
-import type { APIEventDetail } from 'model/Api/types';
+import type { APIEventDetail, PapiReadyEvent } from 'model/Api/types';
import type { OnlineStatusEvent } from 'controllers/OnlineStatus/types';
import type { AnyJson } from '@w3ux/types';
import type { BlockNumberEventDetail } from 'model/Subscribe/BlockNumber/types';
@@ -30,6 +30,7 @@ declare global {
interface DocumentEventMap {
notification: CustomEvent;
'api-status': CustomEvent;
+ 'papi-ready': CustomEvent;
'online-status': CustomEvent;
'new-block-number': CustomEvent;
'new-network-metrics': CustomEvent<{
@@ -66,7 +67,8 @@ type NetworkColor =
export interface Network {
name: NetworkName;
endpoints: {
- lightClient: string;
+ lightClientKey: string;
+ lightClient: () => Promise;
defaultRpcEndpoint: string;
rpcEndpoints: Record;
};
@@ -102,9 +104,11 @@ export interface SystemChain {
units: number;
unit: string;
endpoints: {
- lightClient: string;
+ lightClientKey: string;
+ lightClient: () => Promise;
rpcEndpoints: Record;
};
+ relayChain: NetworkName;
}
export interface PageCategory {
diff --git a/yarn.lock b/yarn.lock
index 5401d1fb8..7eee8079c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -59,7 +59,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0":
+"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0":
version: 7.26.2
resolution: "@babel/code-frame@npm:7.26.2"
dependencies:
@@ -259,6 +259,15 @@ __metadata:
languageName: node
linkType: hard
+"@commander-js/extra-typings@npm:^12.1.0":
+ version: 12.1.0
+ resolution: "@commander-js/extra-typings@npm:12.1.0"
+ peerDependencies:
+ commander: ~12.1.0
+ checksum: 10c0/5d29eaa724b577e2a52a393ad54992924d2559931b8e493ab892477b7a4e878e475c6bf771260f8585d835f7d8e17ae4a2656c191e9595d210ae0b48291c0b3d
+ languageName: node
+ linkType: hard
+
"@dotlottie/common@npm:0.7.11":
version: 0.7.11
resolution: "@dotlottie/common@npm:0.7.11"
@@ -343,6 +352,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/aix-ppc64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/aix-ppc64@npm:0.24.0"
+ conditions: os=aix & cpu=ppc64
+ languageName: node
+ linkType: hard
+
"@esbuild/android-arm64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/android-arm64@npm:0.21.5"
@@ -350,6 +366,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/android-arm64@npm:0.24.0"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/android-arm@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/android-arm@npm:0.21.5"
@@ -357,6 +380,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-arm@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/android-arm@npm:0.24.0"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
"@esbuild/android-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/android-x64@npm:0.21.5"
@@ -364,6 +394,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/android-x64@npm:0.24.0"
+ conditions: os=android & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/darwin-arm64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/darwin-arm64@npm:0.21.5"
@@ -371,6 +408,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/darwin-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/darwin-arm64@npm:0.24.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/darwin-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/darwin-x64@npm:0.21.5"
@@ -378,6 +422,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/darwin-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/darwin-x64@npm:0.24.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/freebsd-arm64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/freebsd-arm64@npm:0.21.5"
@@ -385,6 +436,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/freebsd-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/freebsd-arm64@npm:0.24.0"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/freebsd-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/freebsd-x64@npm:0.21.5"
@@ -392,6 +450,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/freebsd-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/freebsd-x64@npm:0.24.0"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-arm64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-arm64@npm:0.21.5"
@@ -399,6 +464,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-arm64@npm:0.24.0"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-arm@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-arm@npm:0.21.5"
@@ -406,6 +478,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-arm@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-arm@npm:0.24.0"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-ia32@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-ia32@npm:0.21.5"
@@ -413,6 +492,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-ia32@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-ia32@npm:0.24.0"
+ conditions: os=linux & cpu=ia32
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-loong64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-loong64@npm:0.21.5"
@@ -420,6 +506,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-loong64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-loong64@npm:0.24.0"
+ conditions: os=linux & cpu=loong64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-mips64el@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-mips64el@npm:0.21.5"
@@ -427,6 +520,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-mips64el@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-mips64el@npm:0.24.0"
+ conditions: os=linux & cpu=mips64el
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-ppc64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-ppc64@npm:0.21.5"
@@ -434,6 +534,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-ppc64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-ppc64@npm:0.24.0"
+ conditions: os=linux & cpu=ppc64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-riscv64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-riscv64@npm:0.21.5"
@@ -441,6 +548,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-riscv64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-riscv64@npm:0.24.0"
+ conditions: os=linux & cpu=riscv64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-s390x@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-s390x@npm:0.21.5"
@@ -448,6 +562,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-s390x@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-s390x@npm:0.24.0"
+ conditions: os=linux & cpu=s390x
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/linux-x64@npm:0.21.5"
@@ -455,6 +576,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/linux-x64@npm:0.24.0"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/netbsd-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/netbsd-x64@npm:0.21.5"
@@ -462,6 +590,20 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/netbsd-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/netbsd-x64@npm:0.24.0"
+ conditions: os=netbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/openbsd-arm64@npm:0.24.0"
+ conditions: os=openbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/openbsd-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/openbsd-x64@npm:0.21.5"
@@ -469,6 +611,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/openbsd-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/openbsd-x64@npm:0.24.0"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/sunos-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/sunos-x64@npm:0.21.5"
@@ -476,6 +625,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/sunos-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/sunos-x64@npm:0.24.0"
+ conditions: os=sunos & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-arm64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/win32-arm64@npm:0.21.5"
@@ -483,6 +639,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-arm64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/win32-arm64@npm:0.24.0"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-ia32@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/win32-ia32@npm:0.21.5"
@@ -490,6 +653,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-ia32@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/win32-ia32@npm:0.24.0"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-x64@npm:0.21.5":
version: 0.21.5
resolution: "@esbuild/win32-x64@npm:0.21.5"
@@ -497,6 +667,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-x64@npm:0.24.0":
+ version: 0.24.0
+ resolution: "@esbuild/win32-x64@npm:0.24.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0":
version: 4.4.1
resolution: "@eslint-community/eslint-utils@npm:4.4.1"
@@ -868,7 +1045,7 @@ __metadata:
languageName: node
linkType: hard
-"@jridgewell/gen-mapping@npm:^0.3.5":
+"@jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5":
version: 0.3.5
resolution: "@jridgewell/gen-mapping@npm:0.3.5"
dependencies:
@@ -1594,6 +1771,43 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/cli@npm:0.9.17":
+ version: 0.9.17
+ resolution: "@polkadot-api/cli@npm:0.9.17"
+ dependencies:
+ "@commander-js/extra-typings": "npm:^12.1.0"
+ "@polkadot-api/codegen": "npm:0.12.7"
+ "@polkadot-api/ink-contracts": "npm:0.2.0"
+ "@polkadot-api/json-rpc-provider": "npm:0.0.4"
+ "@polkadot-api/known-chains": "npm:0.5.6"
+ "@polkadot-api/metadata-compatibility": "npm:0.1.11"
+ "@polkadot-api/observable-client": "npm:0.6.2"
+ "@polkadot-api/polkadot-sdk-compat": "npm:2.3.1"
+ "@polkadot-api/sm-provider": "npm:0.1.5"
+ "@polkadot-api/smoldot": "npm:0.3.5"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/substrate-client": "npm:0.3.0"
+ "@polkadot-api/utils": "npm:0.1.2"
+ "@polkadot-api/wasm-executor": "npm:^0.1.1"
+ "@polkadot-api/ws-provider": "npm:0.3.4"
+ "@types/node": "npm:^22.2.0"
+ commander: "npm:^12.1.0"
+ execa: "npm:^9.3.0"
+ fs.promises.exists: "npm:^1.1.4"
+ ora: "npm:^8.0.1"
+ read-pkg: "npm:^9.0.1"
+ rxjs: "npm:^7.8.1"
+ tsc-prog: "npm:^2.3.0"
+ tsup: "npm:^8.2.4"
+ typescript: "npm:^5.5.4"
+ write-package: "npm:^7.1.0"
+ bin:
+ papi: dist/main.js
+ polkadot-api: dist/main.js
+ checksum: 10c0/0bdbe91a11e07b0dcc730594c8adfe69fe7e522e7824f07feac51203dec1696e7ba050df209880567467b2813d20559ed85e23a62f71a179c348369f59574265
+ languageName: node
+ linkType: hard
+
"@polkadot-api/client@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
resolution: "@polkadot-api/client@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
@@ -1608,6 +1822,43 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/codegen@npm:0.12.7":
+ version: 0.12.7
+ resolution: "@polkadot-api/codegen@npm:0.12.7"
+ dependencies:
+ "@polkadot-api/ink-contracts": "npm:0.1.2"
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/metadata-compatibility": "npm:0.1.11"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/utils": "npm:0.1.2"
+ checksum: 10c0/3330e74627123d24e0b9c572c172f832060d55b84e87986c8712ee17d9b84e299d90c3f06ff2b8aa1561a21219492bddce723e4c84e16c570f262028aea32333
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/ink-contracts@npm:0.1.2":
+ version: 0.1.2
+ resolution: "@polkadot-api/ink-contracts@npm:0.1.2"
+ dependencies:
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/utils": "npm:0.1.2"
+ scale-ts: "npm:^1.6.1"
+ checksum: 10c0/334203d4c981b691c8f0215746787a7664186c2947ba89818e58034643ab4f552ead612f8cf0b1f6cf29ad13696433717f01a75fde00fd6cd7a90cf0492e61f1
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/ink-contracts@npm:0.2.0":
+ version: 0.2.0
+ resolution: "@polkadot-api/ink-contracts@npm:0.2.0"
+ dependencies:
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/utils": "npm:0.1.2"
+ scale-ts: "npm:^1.6.1"
+ checksum: 10c0/c5f2457452047c0511bc3092cf61fbe1aafdc665fe5a8b60227fce57f587effea3e1f8d145ae3e6db1631a84286f40847cbf2c74f4f580e643151d2f09b92676
+ languageName: node
+ linkType: hard
+
"@polkadot-api/json-rpc-provider-proxy@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
@@ -1615,6 +1866,13 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/json-rpc-provider-proxy@npm:0.2.3":
+ version: 0.2.3
+ resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.2.3"
+ checksum: 10c0/eeaa46751fba879c03bde24a06a9aa4941bd901d166e1c49ae8d3596b7c6e8a868d4f25ba75c4a9761283953c2511057a51dd3ae27e4c0d7823d55f55af384b9
+ languageName: node
+ linkType: hard
+
"@polkadot-api/json-rpc-provider-proxy@npm:^0.1.0":
version: 0.1.0
resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.1.0"
@@ -1636,6 +1894,29 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/json-rpc-provider@npm:0.0.4":
+ version: 0.0.4
+ resolution: "@polkadot-api/json-rpc-provider@npm:0.0.4"
+ checksum: 10c0/5615394380bff2d8885592c8001055f1b006e3dd2f650b6a0e41ec836d61e903d78cc4ed06297827020523b0eecc9dff0af661fed7ae82523c97e294a2dc2e27
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/known-chains@npm:0.5.6":
+ version: 0.5.6
+ resolution: "@polkadot-api/known-chains@npm:0.5.6"
+ checksum: 10c0/1767760ecdf834540290bdde8ab823907121b0ee3fee071bb393f00625b419299168c71cbcfaa6e6af67789cc5f4e4083a0020c955540b5f379b120895b44556
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/logs-provider@npm:0.0.6":
+ version: 0.0.6
+ resolution: "@polkadot-api/logs-provider@npm:0.0.6"
+ dependencies:
+ "@polkadot-api/json-rpc-provider": "npm:0.0.4"
+ checksum: 10c0/0c7d22b7a9cc495539f3f4a61d0d77882139bcfbb8159d8ffadbc7f2b6a8dd093f217fd2266df60417bc7b23582d2c3659052e17bb9b1be664abf76edf7ce558
+ languageName: node
+ linkType: hard
+
"@polkadot-api/merkleize-metadata@npm:^1.1.4":
version: 1.1.9
resolution: "@polkadot-api/merkleize-metadata@npm:1.1.9"
@@ -1677,6 +1958,30 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/metadata-compatibility@npm:0.1.11":
+ version: 0.1.11
+ resolution: "@polkadot-api/metadata-compatibility@npm:0.1.11"
+ dependencies:
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ checksum: 10c0/66397a323d272ea33fdf71fffd0ed4085d5a7d1333b07af21932cf19911cf8271905cc8489a7d40b67319ea83b5d5c2c056e692a2059c99ee22bec440167ae07
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/observable-client@npm:0.6.2":
+ version: 0.6.2
+ resolution: "@polkadot-api/observable-client@npm:0.6.2"
+ dependencies:
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/utils": "npm:0.1.2"
+ peerDependencies:
+ "@polkadot-api/substrate-client": 0.3.0
+ rxjs: ">=7.8.0"
+ checksum: 10c0/dd5e767a16c70566776ee24aee62e1c4029b72bf1952d0b26e37da65b04c36c288a50ffdaf644b999d05fcb01da9e3aed4112b8ac0ef258d9d3135b4478d1ed0
+ languageName: node
+ linkType: hard
+
"@polkadot-api/observable-client@npm:^0.3.0":
version: 0.3.2
resolution: "@polkadot-api/observable-client@npm:0.3.2"
@@ -1691,6 +1996,82 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/pjs-signer@npm:0.6.0":
+ version: 0.6.0
+ resolution: "@polkadot-api/pjs-signer@npm:0.6.0"
+ dependencies:
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/polkadot-signer": "npm:0.1.6"
+ "@polkadot-api/signers-common": "npm:0.1.1"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/utils": "npm:0.1.2"
+ checksum: 10c0/efe86166d5f7f62cb9c94f555e56d56d2f73c2bef18cfb93a0e7004e0dc67d08abe0ec75712e03cb8506615718f17e06300dc7dfe50831fbbdd7286485223a24
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/polkadot-sdk-compat@npm:2.3.1":
+ version: 2.3.1
+ resolution: "@polkadot-api/polkadot-sdk-compat@npm:2.3.1"
+ dependencies:
+ "@polkadot-api/json-rpc-provider": "npm:0.0.4"
+ checksum: 10c0/19f55588fbac5b72a8e0d54e7c5958b3de76907217bba94118aa409e86b1dc1a86f392da724a258a409678fd00ae21c07d0ade566a6238a84abd10cbed6952c9
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/polkadot-signer@npm:0.1.6":
+ version: 0.1.6
+ resolution: "@polkadot-api/polkadot-signer@npm:0.1.6"
+ checksum: 10c0/26ab65ac02cfc9dcc8b9539f44f0e72f8faa8dbbb7cc68c5922e2ebdf71bcca0641e70f1fb0fec46de4f98f36448164c7025ef68bc21fa635b8bbb15f5731f10
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/signer@npm:0.1.10":
+ version: 0.1.10
+ resolution: "@polkadot-api/signer@npm:0.1.10"
+ dependencies:
+ "@noble/hashes": "npm:^1.5.0"
+ "@polkadot-api/polkadot-signer": "npm:0.1.6"
+ "@polkadot-api/signers-common": "npm:0.1.1"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/utils": "npm:0.1.2"
+ checksum: 10c0/25e2f5dcb02945aad2cb777e52f87a5dfcc0f0b46238717068419a9efa67f04f40de8ce05ec4ab4f046f028590f4729f2a0a019b44e8e3c8fa66a692713344de
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/signers-common@npm:0.1.1":
+ version: 0.1.1
+ resolution: "@polkadot-api/signers-common@npm:0.1.1"
+ dependencies:
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/polkadot-signer": "npm:0.1.6"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/utils": "npm:0.1.2"
+ checksum: 10c0/17f1811e568ae3d655ae90dffdc3dd7327dc1d99673f6362f241c1e5595e188797755cb4b4bcbfae321385dadb38258b16725ea89e5de1fe8088a2dd227c9b34
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/sm-provider@npm:0.1.5":
+ version: 0.1.5
+ resolution: "@polkadot-api/sm-provider@npm:0.1.5"
+ dependencies:
+ "@polkadot-api/json-rpc-provider": "npm:0.0.4"
+ "@polkadot-api/json-rpc-provider-proxy": "npm:0.2.3"
+ peerDependencies:
+ "@polkadot-api/smoldot": ">=0.3"
+ checksum: 10c0/d87dfc11d5d491c0bdb35e2a788641c8e1ec738d47885c1929c29d22ea03eaaf14a7ea355507b8817a42f9d37f0ae265ee138e6fd46618ca47cc6622046a302b
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/smoldot@npm:0.3.5":
+ version: 0.3.5
+ resolution: "@polkadot-api/smoldot@npm:0.3.5"
+ dependencies:
+ "@types/node": "npm:^22.2.0"
+ smoldot: "npm:2.0.31"
+ checksum: 10c0/a9658a06bf4a3bcb5127dcf3a58adf732c43be4c683cdd7054dadfb55122f32ce990aab866deb0a572340faadfdf9813ef2f938ae220be58628be67eeb14342d
+ languageName: node
+ linkType: hard
+
"@polkadot-api/substrate-bindings@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
resolution: "@polkadot-api/substrate-bindings@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
@@ -1734,6 +2115,16 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/substrate-client@npm:0.3.0":
+ version: 0.3.0
+ resolution: "@polkadot-api/substrate-client@npm:0.3.0"
+ dependencies:
+ "@polkadot-api/json-rpc-provider": "npm:0.0.4"
+ "@polkadot-api/utils": "npm:0.1.2"
+ checksum: 10c0/a1eba558065f596f2fecf40d4bcef4e3ea50344b76bf5e890bbb17e4ff0b1fb251cf484bf2b8ef49ebcce5c2fc84ee1617e0769d2d6f740faf0caa623d8a6a12
+ languageName: node
+ linkType: hard
+
"@polkadot-api/substrate-client@npm:^0.1.2":
version: 0.1.4
resolution: "@polkadot-api/substrate-client@npm:0.1.4"
@@ -1765,6 +2156,24 @@ __metadata:
languageName: node
linkType: hard
+"@polkadot-api/wasm-executor@npm:^0.1.1":
+ version: 0.1.2
+ resolution: "@polkadot-api/wasm-executor@npm:0.1.2"
+ checksum: 10c0/0577111cf7ee12e1606ba863385f50670f2d073e9032efd8365e578f03f4a8b01e699641e19b2aec15e36832aa3b6b0724951fa84d23e87492d0532f55e291bf
+ languageName: node
+ linkType: hard
+
+"@polkadot-api/ws-provider@npm:0.3.4":
+ version: 0.3.4
+ resolution: "@polkadot-api/ws-provider@npm:0.3.4"
+ dependencies:
+ "@polkadot-api/json-rpc-provider": "npm:0.0.4"
+ "@polkadot-api/json-rpc-provider-proxy": "npm:0.2.3"
+ ws: "npm:^8.18.0"
+ checksum: 10c0/39243a8f1545dd8191c62f43ee05e2450b5a7758adfe974f2d4a965546ea5001f19ff7ca14c87d1655dba1526ad08f8118a2cc6597f53d3a3172860b5da4d10d
+ languageName: node
+ linkType: hard
+
"@polkadot/api-augment@npm:10.13.1":
version: 10.13.1
resolution: "@polkadot/api-augment@npm:10.13.1"
@@ -2834,6 +3243,13 @@ __metadata:
languageName: node
linkType: hard
+"@sec-ant/readable-stream@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "@sec-ant/readable-stream@npm:0.4.1"
+ checksum: 10c0/64e9e9cf161e848067a5bf60cdc04d18495dc28bb63a8d9f8993e4dd99b91ad34e4b563c85de17d91ffb177ec17a0664991d2e115f6543e73236a906068987af
+ languageName: node
+ linkType: hard
+
"@sinclair/typebox@npm:^0.27.8":
version: 0.27.8
resolution: "@sinclair/typebox@npm:0.27.8"
@@ -2841,6 +3257,13 @@ __metadata:
languageName: node
linkType: hard
+"@sindresorhus/merge-streams@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "@sindresorhus/merge-streams@npm:4.0.0"
+ checksum: 10c0/482ee543629aa1933b332f811a1ae805a213681ecdd98c042b1c1b89387df63e7812248bb4df3910b02b3cc5589d3d73e4393f30e197c9dde18046ccd471fc6b
+ languageName: node
+ linkType: hard
+
"@socket.io/component-emitter@npm:~3.1.0":
version: 3.1.2
resolution: "@socket.io/component-emitter@npm:3.1.2"
@@ -3472,7 +3895,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:*":
+"@types/node@npm:*, @types/node@npm:^22.2.0":
version: 22.9.0
resolution: "@types/node@npm:22.9.0"
dependencies:
@@ -3481,6 +3904,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/normalize-package-data@npm:^2.4.3":
+ version: 2.4.4
+ resolution: "@types/normalize-package-data@npm:2.4.4"
+ checksum: 10c0/aef7bb9b015883d6f4119c423dd28c4bdc17b0e8a0ccf112c78b4fe0e91fbc4af7c6204b04bba0e199a57d2f3fbbd5b4a14bf8739bf9d2a39b2a0aad545e0f86
+ languageName: node
+ linkType: hard
+
"@types/prop-types@npm:*":
version: 15.7.13
resolution: "@types/prop-types@npm:15.7.13"
@@ -4410,6 +4840,13 @@ __metadata:
languageName: node
linkType: hard
+"any-promise@npm:^1.0.0":
+ version: 1.3.0
+ resolution: "any-promise@npm:1.3.0"
+ checksum: 10c0/60f0298ed34c74fef50daab88e8dab786036ed5a7fad02e012ab57e376e0a0b4b29e83b95ea9b5e7d89df762f5f25119b83e00706ecaccb22cfbacee98d74889
+ languageName: node
+ linkType: hard
+
"anymatch@npm:^3.1.3, anymatch@npm:~3.1.2":
version: 3.1.3
resolution: "anymatch@npm:3.1.3"
@@ -4460,6 +4897,7 @@ __metadata:
lodash.debounce: "npm:^4.0.8"
lodash.throttle: "npm:^4.1.1"
plugin-staking-api: "workspace:*"
+ polkadot-api: "npm:^1.7.3"
qrcode-generator: "npm:1.4.4"
rc-slider: "npm:^11.1.6"
react: "npm:^18.3.1"
@@ -4802,6 +5240,17 @@ __metadata:
languageName: node
linkType: hard
+"bundle-require@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "bundle-require@npm:5.0.0"
+ dependencies:
+ load-tsconfig: "npm:^0.2.3"
+ peerDependencies:
+ esbuild: ">=0.18"
+ checksum: 10c0/92c46df02586e0ebd66ee4831c9b5775adb3c32a43fe2b2aaf7bc675135c141f751de6a9a26b146d64c607c5b40f9eef5f10dce3c364f602d4bed268444c32c6
+ languageName: node
+ linkType: hard
+
"cac@npm:^6.7.14":
version: 6.7.14
resolution: "cac@npm:6.7.14"
@@ -4919,6 +5368,13 @@ __metadata:
languageName: node
linkType: hard
+"chalk@npm:^5.3.0":
+ version: 5.3.0
+ resolution: "chalk@npm:5.3.0"
+ checksum: 10c0/8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09
+ languageName: node
+ linkType: hard
+
"chart.js@npm:^4.4.4":
version: 4.4.6
resolution: "chart.js@npm:4.4.6"
@@ -4956,6 +5412,15 @@ __metadata:
languageName: node
linkType: hard
+"chokidar@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "chokidar@npm:4.0.1"
+ dependencies:
+ readdirp: "npm:^4.0.1"
+ checksum: 10c0/4bb7a3adc304059810bb6c420c43261a15bb44f610d77c35547addc84faa0374265c3adc67f25d06f363d9a4571962b02679268c40de07676d260de1986efea9
+ languageName: node
+ linkType: hard
+
"chownr@npm:^2.0.0":
version: 2.0.0
resolution: "chownr@npm:2.0.0"
@@ -4993,11 +5458,27 @@ __metadata:
languageName: node
linkType: hard
-"clipboardy@npm:^4.0.0":
- version: 4.0.0
- resolution: "clipboardy@npm:4.0.0"
+"cli-cursor@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "cli-cursor@npm:5.0.0"
dependencies:
- execa: "npm:^8.0.1"
+ restore-cursor: "npm:^5.0.0"
+ checksum: 10c0/7ec62f69b79f6734ab209a3e4dbdc8af7422d44d360a7cb1efa8a0887bbe466a6e625650c466fe4359aee44dbe2dc0b6994b583d40a05d0808a5cb193641d220
+ languageName: node
+ linkType: hard
+
+"cli-spinners@npm:^2.9.2":
+ version: 2.9.2
+ resolution: "cli-spinners@npm:2.9.2"
+ checksum: 10c0/907a1c227ddf0d7a101e7ab8b300affc742ead4b4ebe920a5bf1bc6d45dce2958fcd195eb28fa25275062fe6fa9b109b93b63bc8033396ed3bcb50297008b3a3
+ languageName: node
+ linkType: hard
+
+"clipboardy@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "clipboardy@npm:4.0.0"
+ dependencies:
+ execa: "npm:^8.0.1"
is-wsl: "npm:^3.1.0"
is64bit: "npm:^2.0.0"
checksum: 10c0/02bb5f3d0a772bd84ec26a3566c72c2319a9f3b4cb8338370c3bffcf0073c80b834abe1a6945bea4f2cbea28e1627a975aaac577e3f61a868d924ce79138b041
@@ -5078,6 +5559,20 @@ __metadata:
languageName: node
linkType: hard
+"commander@npm:^12.1.0":
+ version: 12.1.0
+ resolution: "commander@npm:12.1.0"
+ checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9
+ languageName: node
+ linkType: hard
+
+"commander@npm:^4.0.0":
+ version: 4.1.1
+ resolution: "commander@npm:4.1.1"
+ checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab
+ languageName: node
+ linkType: hard
+
"commander@npm:^8.0.0":
version: 8.3.0
resolution: "commander@npm:8.3.0"
@@ -5287,7 +5782,7 @@ __metadata:
languageName: node
linkType: hard
-"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:~4.3.1, debug@npm:~4.3.2":
+"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.7, debug@npm:~4.3.1, debug@npm:~4.3.2":
version: 4.3.7
resolution: "debug@npm:4.3.7"
dependencies:
@@ -5345,6 +5840,13 @@ __metadata:
languageName: node
linkType: hard
+"deepmerge-ts@npm:^7.1.0":
+ version: 7.1.3
+ resolution: "deepmerge-ts@npm:7.1.3"
+ checksum: 10c0/c9cfe7742a2c8f785302378b004381e1b831e3307ffe0c17be4b98fd87f347cb52a550aa9ff9ee0608b97f25400972ab79484f3836d77ec733828b10c8dcc522
+ languageName: node
+ linkType: hard
+
"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4":
version: 1.1.4
resolution: "define-data-property@npm:1.1.4"
@@ -5402,6 +5904,13 @@ __metadata:
languageName: node
linkType: hard
+"detect-indent@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "detect-indent@npm:7.0.1"
+ checksum: 10c0/47b6e3e3dda603c386e73b129f3e84844ae59bc2615f5072becf3cc02eab400bed5a4e6379c49d0b18cf630e80c2b07e87e0038b777addbc6ef793ad77dd05bc
+ languageName: node
+ linkType: hard
+
"detect-libc@npm:^1.0.3":
version: 1.0.3
resolution: "detect-libc@npm:1.0.3"
@@ -5522,6 +6031,13 @@ __metadata:
languageName: node
linkType: hard
+"emoji-regex@npm:^10.3.0":
+ version: 10.4.0
+ resolution: "emoji-regex@npm:10.4.0"
+ checksum: 10c0/a3fcedfc58bfcce21a05a5f36a529d81e88d602100145fcca3dc6f795e3c8acc4fc18fe773fbf9b6d6e9371205edb3afa2668ec3473fa2aa7fd47d2a9d46482d
+ languageName: node
+ linkType: hard
+
"emoji-regex@npm:^8.0.0":
version: 8.0.0
resolution: "emoji-regex@npm:8.0.0"
@@ -5843,6 +6359,89 @@ __metadata:
languageName: node
linkType: hard
+"esbuild@npm:^0.24.0":
+ version: 0.24.0
+ resolution: "esbuild@npm:0.24.0"
+ dependencies:
+ "@esbuild/aix-ppc64": "npm:0.24.0"
+ "@esbuild/android-arm": "npm:0.24.0"
+ "@esbuild/android-arm64": "npm:0.24.0"
+ "@esbuild/android-x64": "npm:0.24.0"
+ "@esbuild/darwin-arm64": "npm:0.24.0"
+ "@esbuild/darwin-x64": "npm:0.24.0"
+ "@esbuild/freebsd-arm64": "npm:0.24.0"
+ "@esbuild/freebsd-x64": "npm:0.24.0"
+ "@esbuild/linux-arm": "npm:0.24.0"
+ "@esbuild/linux-arm64": "npm:0.24.0"
+ "@esbuild/linux-ia32": "npm:0.24.0"
+ "@esbuild/linux-loong64": "npm:0.24.0"
+ "@esbuild/linux-mips64el": "npm:0.24.0"
+ "@esbuild/linux-ppc64": "npm:0.24.0"
+ "@esbuild/linux-riscv64": "npm:0.24.0"
+ "@esbuild/linux-s390x": "npm:0.24.0"
+ "@esbuild/linux-x64": "npm:0.24.0"
+ "@esbuild/netbsd-x64": "npm:0.24.0"
+ "@esbuild/openbsd-arm64": "npm:0.24.0"
+ "@esbuild/openbsd-x64": "npm:0.24.0"
+ "@esbuild/sunos-x64": "npm:0.24.0"
+ "@esbuild/win32-arm64": "npm:0.24.0"
+ "@esbuild/win32-ia32": "npm:0.24.0"
+ "@esbuild/win32-x64": "npm:0.24.0"
+ dependenciesMeta:
+ "@esbuild/aix-ppc64":
+ optional: true
+ "@esbuild/android-arm":
+ optional: true
+ "@esbuild/android-arm64":
+ optional: true
+ "@esbuild/android-x64":
+ optional: true
+ "@esbuild/darwin-arm64":
+ optional: true
+ "@esbuild/darwin-x64":
+ optional: true
+ "@esbuild/freebsd-arm64":
+ optional: true
+ "@esbuild/freebsd-x64":
+ optional: true
+ "@esbuild/linux-arm":
+ optional: true
+ "@esbuild/linux-arm64":
+ optional: true
+ "@esbuild/linux-ia32":
+ optional: true
+ "@esbuild/linux-loong64":
+ optional: true
+ "@esbuild/linux-mips64el":
+ optional: true
+ "@esbuild/linux-ppc64":
+ optional: true
+ "@esbuild/linux-riscv64":
+ optional: true
+ "@esbuild/linux-s390x":
+ optional: true
+ "@esbuild/linux-x64":
+ optional: true
+ "@esbuild/netbsd-x64":
+ optional: true
+ "@esbuild/openbsd-arm64":
+ optional: true
+ "@esbuild/openbsd-x64":
+ optional: true
+ "@esbuild/sunos-x64":
+ optional: true
+ "@esbuild/win32-arm64":
+ optional: true
+ "@esbuild/win32-ia32":
+ optional: true
+ "@esbuild/win32-x64":
+ optional: true
+ bin:
+ esbuild: bin/esbuild
+ checksum: 10c0/9f1aadd8d64f3bff422ae78387e66e51a5e09de6935a6f987b6e4e189ed00fdc2d1bc03d2e33633b094008529c8b6e06c7ad1a9782fb09fec223bf95998c0683
+ languageName: node
+ linkType: hard
+
"escalade@npm:^3.1.1, escalade@npm:^3.2.0":
version: 3.2.0
resolution: "escalade@npm:3.2.0"
@@ -6275,6 +6874,26 @@ __metadata:
languageName: node
linkType: hard
+"execa@npm:^9.3.0":
+ version: 9.5.1
+ resolution: "execa@npm:9.5.1"
+ dependencies:
+ "@sindresorhus/merge-streams": "npm:^4.0.0"
+ cross-spawn: "npm:^7.0.3"
+ figures: "npm:^6.1.0"
+ get-stream: "npm:^9.0.0"
+ human-signals: "npm:^8.0.0"
+ is-plain-obj: "npm:^4.1.0"
+ is-stream: "npm:^4.0.1"
+ npm-run-path: "npm:^6.0.0"
+ pretty-ms: "npm:^9.0.0"
+ signal-exit: "npm:^4.1.0"
+ strip-final-newline: "npm:^4.0.0"
+ yoctocolors: "npm:^2.0.0"
+ checksum: 10c0/1a628d535c5a088f9e17a735bb3143efc4198095392b319ba877b2975d5c3c57724536dccb6f68f1cd9b3af331c5a9e8c1aeb338d52ab316b1e008ff453374a7
+ languageName: node
+ linkType: hard
+
"exponential-backoff@npm:^3.1.1":
version: 3.1.1
resolution: "exponential-backoff@npm:3.1.1"
@@ -6356,6 +6975,18 @@ __metadata:
languageName: node
linkType: hard
+"fdir@npm:^6.4.2":
+ version: 6.4.2
+ resolution: "fdir@npm:6.4.2"
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+ checksum: 10c0/34829886f34a3ca4170eca7c7180ec4de51a3abb4d380344063c0ae2e289b11d2ba8b724afee974598c83027fea363ff598caf2b51bc4e6b1e0d8b80cc530573
+ languageName: node
+ linkType: hard
+
"fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4":
version: 3.2.0
resolution: "fetch-blob@npm:3.2.0"
@@ -6373,6 +7004,15 @@ __metadata:
languageName: node
linkType: hard
+"figures@npm:^6.1.0":
+ version: 6.1.0
+ resolution: "figures@npm:6.1.0"
+ dependencies:
+ is-unicode-supported: "npm:^2.0.0"
+ checksum: 10c0/9159df4264d62ef447a3931537de92f5012210cf5135c35c010df50a2169377581378149abfe1eb238bd6acbba1c0d547b1f18e0af6eee49e30363cedaffcfe4
+ languageName: node
+ linkType: hard
+
"file-entry-cache@npm:^6.0.1":
version: 6.0.1
resolution: "file-entry-cache@npm:6.0.1"
@@ -6534,6 +7174,13 @@ __metadata:
languageName: node
linkType: hard
+"fs.promises.exists@npm:^1.1.4":
+ version: 1.1.4
+ resolution: "fs.promises.exists@npm:1.1.4"
+ checksum: 10c0/6e200a97e869c8b84b4dabc5c963d87d20db8704fa12098773b472a61651c0a822b651807ff883e09b8480c41f5184acb65abdd9965b950b3cb2b473b10c3c0f
+ languageName: node
+ linkType: hard
+
"fs.realpath@npm:^1.0.0":
version: 1.0.0
resolution: "fs.realpath@npm:1.0.0"
@@ -6600,6 +7247,13 @@ __metadata:
languageName: node
linkType: hard
+"get-east-asian-width@npm:^1.0.0":
+ version: 1.3.0
+ resolution: "get-east-asian-width@npm:1.3.0"
+ checksum: 10c0/1a049ba697e0f9a4d5514c4623781c5246982bdb61082da6b5ae6c33d838e52ce6726407df285cdbb27ec1908b333cf2820989bd3e986e37bb20979437fdf34b
+ languageName: node
+ linkType: hard
+
"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2":
version: 2.0.2
resolution: "get-func-name@npm:2.0.2"
@@ -6634,6 +7288,16 @@ __metadata:
languageName: node
linkType: hard
+"get-stream@npm:^9.0.0":
+ version: 9.0.1
+ resolution: "get-stream@npm:9.0.1"
+ dependencies:
+ "@sec-ant/readable-stream": "npm:^0.4.1"
+ is-stream: "npm:^4.0.1"
+ checksum: 10c0/d70e73857f2eea1826ac570c3a912757dcfbe8a718a033fa0c23e12ac8e7d633195b01710e0559af574cbb5af101009b42df7b6f6b29ceec8dbdf7291931b948
+ languageName: node
+ linkType: hard
+
"get-symbol-description@npm:^1.0.2":
version: 1.0.2
resolution: "get-symbol-description@npm:1.0.2"
@@ -6900,6 +7564,15 @@ __metadata:
languageName: node
linkType: hard
+"hosted-git-info@npm:^7.0.0":
+ version: 7.0.2
+ resolution: "hosted-git-info@npm:7.0.2"
+ dependencies:
+ lru-cache: "npm:^10.0.1"
+ checksum: 10c0/b19dbd92d3c0b4b0f1513cf79b0fc189f54d6af2129eeb201de2e9baaa711f1936929c848b866d9c8667a0f956f34bf4f07418c12be1ee9ca74fd9246335ca1f
+ languageName: node
+ linkType: hard
+
"howler@npm:^2.2.3":
version: 2.2.4
resolution: "howler@npm:2.2.4"
@@ -6964,6 +7637,13 @@ __metadata:
languageName: node
linkType: hard
+"human-signals@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "human-signals@npm:8.0.0"
+ checksum: 10c0/e4dac4f7d3eb791ed04129fc6a85bd454a9102d3e3b76c911d0db7057ebd60b2956b435b5b5712aec18960488ede3c21ef7c56e42cdd70760c0d84d3c05cd92e
+ languageName: node
+ linkType: hard
+
"i18next-browser-languagedetector@npm:7.1.0":
version: 7.1.0
resolution: "i18next-browser-languagedetector@npm:7.1.0"
@@ -7078,6 +7758,13 @@ __metadata:
languageName: node
linkType: hard
+"index-to-position@npm:^0.1.2":
+ version: 0.1.2
+ resolution: "index-to-position@npm:0.1.2"
+ checksum: 10c0/7c91bde8bafc22684b74a7a24915bee4691cba48352ddb4ebe3b20a3a87bc0fa7a05f586137245ca8f92222a11f341f7631ff7f38cd78a523505d2d02dbfa257
+ languageName: node
+ linkType: hard
+
"inflight@npm:^1.0.4":
version: 1.0.6
resolution: "inflight@npm:1.0.6"
@@ -7316,6 +8003,13 @@ __metadata:
languageName: node
linkType: hard
+"is-interactive@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "is-interactive@npm:2.0.0"
+ checksum: 10c0/801c8f6064f85199dc6bf99b5dd98db3282e930c3bc197b32f2c5b89313bb578a07d1b8a01365c4348c2927229234f3681eb861b9c2c92bee72ff397390fa600
+ languageName: node
+ linkType: hard
+
"is-lambda@npm:^1.0.1":
version: 1.0.1
resolution: "is-lambda@npm:1.0.1"
@@ -7360,6 +8054,13 @@ __metadata:
languageName: node
linkType: hard
+"is-plain-obj@npm:^4.0.0, is-plain-obj@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "is-plain-obj@npm:4.1.0"
+ checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e
+ languageName: node
+ linkType: hard
+
"is-regex@npm:^1.1.4":
version: 1.1.4
resolution: "is-regex@npm:1.1.4"
@@ -7400,6 +8101,13 @@ __metadata:
languageName: node
linkType: hard
+"is-stream@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "is-stream@npm:4.0.1"
+ checksum: 10c0/2706c7f19b851327ba374687bc4a3940805e14ca496dc672b9629e744d143b1ad9c6f1b162dece81c7bfbc0f83b32b61ccc19ad2e05aad2dd7af347408f60c7f
+ languageName: node
+ linkType: hard
+
"is-string@npm:^1.0.5, is-string@npm:^1.0.7":
version: 1.0.7
resolution: "is-string@npm:1.0.7"
@@ -7427,6 +8135,20 @@ __metadata:
languageName: node
linkType: hard
+"is-unicode-supported@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "is-unicode-supported@npm:1.3.0"
+ checksum: 10c0/b8674ea95d869f6faabddc6a484767207058b91aea0250803cbf1221345cb0c56f466d4ecea375dc77f6633d248d33c47bd296fb8f4cdba0b4edba8917e83d8a
+ languageName: node
+ linkType: hard
+
+"is-unicode-supported@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "is-unicode-supported@npm:2.1.0"
+ checksum: 10c0/a0f53e9a7c1fdbcf2d2ef6e40d4736fdffff1c9f8944c75e15425118ff3610172c87bf7bc6c34d3903b04be59790bb2212ddbe21ee65b5a97030fc50370545a5
+ languageName: node
+ linkType: hard
+
"is-weakmap@npm:^2.0.2":
version: 2.0.2
resolution: "is-weakmap@npm:2.0.2"
@@ -7552,6 +8274,13 @@ __metadata:
languageName: node
linkType: hard
+"joycon@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "joycon@npm:3.1.1"
+ checksum: 10c0/131fb1e98c9065d067fd49b6e685487ac4ad4d254191d7aa2c9e3b90f4e9ca70430c43cad001602bdbdabcf58717d3b5c5b7461c1bd8e39478c8de706b3fe6ae
+ languageName: node
+ linkType: hard
+
"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
version: 4.0.0
resolution: "js-tokens@npm:4.0.0"
@@ -7728,6 +8457,13 @@ __metadata:
languageName: node
linkType: hard
+"lilconfig@npm:^3.1.1":
+ version: 3.1.2
+ resolution: "lilconfig@npm:3.1.2"
+ checksum: 10c0/f059630b1a9bddaeba83059db00c672b64dc14074e9f232adce32b38ca1b5686ab737eb665c5ba3c32f147f0002b4bee7311ad0386a9b98547b5623e87071fbe
+ languageName: node
+ linkType: hard
+
"lines-and-columns@npm:^1.1.6":
version: 1.2.4
resolution: "lines-and-columns@npm:1.2.4"
@@ -7795,6 +8531,13 @@ __metadata:
languageName: node
linkType: hard
+"load-tsconfig@npm:^0.2.3":
+ version: 0.2.5
+ resolution: "load-tsconfig@npm:0.2.5"
+ checksum: 10c0/bf2823dd26389d3497b6567f07435c5a7a58d9df82e879b0b3892f87d8db26900f84c85bc329ef41c0540c0d6a448d1c23ddc64a80f3ff6838b940f3915a3fcb
+ languageName: node
+ linkType: hard
+
"local-pkg@npm:^0.5.0":
version: 0.5.0
resolution: "local-pkg@npm:0.5.0"
@@ -7844,6 +8587,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash.sortby@npm:^4.7.0":
+ version: 4.7.0
+ resolution: "lodash.sortby@npm:4.7.0"
+ checksum: 10c0/fc48fb54ff7669f33bb32997cab9460757ee99fafaf72400b261c3e10fde21538e47d8cfcbe6a25a31bcb5b7b727c27d52626386fc2de24eb059a6d64a89cdf5
+ languageName: node
+ linkType: hard
+
"lodash.throttle@npm:^4.1.1":
version: 4.1.1
resolution: "lodash.throttle@npm:4.1.1"
@@ -7851,6 +8601,16 @@ __metadata:
languageName: node
linkType: hard
+"log-symbols@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "log-symbols@npm:6.0.0"
+ dependencies:
+ chalk: "npm:^5.3.0"
+ is-unicode-supported: "npm:^1.3.0"
+ checksum: 10c0/36636cacedba8f067d2deb4aad44e91a89d9efb3ead27e1846e7b82c9a10ea2e3a7bd6ce28a7ca616bebc60954ff25c67b0f92d20a6a746bb3cc52c3701891f6
+ languageName: node
+ linkType: hard
+
"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0":
version: 1.4.0
resolution: "loose-envify@npm:1.4.0"
@@ -7995,6 +8755,13 @@ __metadata:
languageName: node
linkType: hard
+"mimic-function@npm:^5.0.0":
+ version: 5.0.1
+ resolution: "mimic-function@npm:5.0.1"
+ checksum: 10c0/f3d9464dd1816ecf6bdf2aec6ba32c0728022039d992f178237d8e289b48764fee4131319e72eedd4f7f094e22ded0af836c3187a7edc4595d28dd74368fd81d
+ languageName: node
+ linkType: hard
+
"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1":
version: 1.0.1
resolution: "minimalistic-assert@npm:1.0.1"
@@ -8186,6 +8953,17 @@ __metadata:
languageName: node
linkType: hard
+"mz@npm:^2.7.0":
+ version: 2.7.0
+ resolution: "mz@npm:2.7.0"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ object-assign: "npm:^4.0.1"
+ thenify-all: "npm:^1.0.0"
+ checksum: 10c0/103114e93f87362f0b56ab5b2e7245051ad0276b646e3902c98397d18bb8f4a77f2ea4a2c9d3ad516034ea3a56553b60d3f5f78220001ca4c404bd711bd0af39
+ languageName: node
+ linkType: hard
+
"nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
@@ -8350,6 +9128,17 @@ __metadata:
languageName: node
linkType: hard
+"normalize-package-data@npm:^6.0.0":
+ version: 6.0.2
+ resolution: "normalize-package-data@npm:6.0.2"
+ dependencies:
+ hosted-git-info: "npm:^7.0.0"
+ semver: "npm:^7.3.5"
+ validate-npm-package-license: "npm:^3.0.4"
+ checksum: 10c0/7e32174e7f5575ede6d3d449593247183880122b4967d4ae6edb28cea5769ca025defda54fc91ec0e3c972fdb5ab11f9284606ba278826171b264cb16a9311ef
+ languageName: node
+ linkType: hard
+
"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0":
version: 3.0.0
resolution: "normalize-path@npm:3.0.0"
@@ -8375,6 +9164,16 @@ __metadata:
languageName: node
linkType: hard
+"npm-run-path@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "npm-run-path@npm:6.0.0"
+ dependencies:
+ path-key: "npm:^4.0.0"
+ unicorn-magic: "npm:^0.3.0"
+ checksum: 10c0/b223c8a0dcd608abf95363ea5c3c0ccc3cd877daf0102eaf1b0f2390d6858d8337fbb7c443af2403b067a7d2c116d10691ecd22ab3c5273c44da1ff8d07753bd
+ languageName: node
+ linkType: hard
+
"obj-multiplex@npm:^1.0.0":
version: 1.0.0
resolution: "obj-multiplex@npm:1.0.0"
@@ -8386,7 +9185,7 @@ __metadata:
languageName: node
linkType: hard
-"object-assign@npm:^4.1.1":
+"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1":
version: 4.1.1
resolution: "object-assign@npm:4.1.1"
checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
@@ -8507,6 +9306,15 @@ __metadata:
languageName: node
linkType: hard
+"onetime@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "onetime@npm:7.0.0"
+ dependencies:
+ mimic-function: "npm:^5.0.0"
+ checksum: 10c0/5cb9179d74b63f52a196a2e7037ba2b9a893245a5532d3f44360012005c9cadb60851d56716ebff18a6f47129dab7168022445df47c2aff3b276d92585ed1221
+ languageName: node
+ linkType: hard
+
"open@npm:^8.4.0":
version: 8.4.2
resolution: "open@npm:8.4.2"
@@ -8544,6 +9352,23 @@ __metadata:
languageName: node
linkType: hard
+"ora@npm:^8.0.1":
+ version: 8.1.1
+ resolution: "ora@npm:8.1.1"
+ dependencies:
+ chalk: "npm:^5.3.0"
+ cli-cursor: "npm:^5.0.0"
+ cli-spinners: "npm:^2.9.2"
+ is-interactive: "npm:^2.0.0"
+ is-unicode-supported: "npm:^2.0.0"
+ log-symbols: "npm:^6.0.0"
+ stdin-discarder: "npm:^0.2.2"
+ string-width: "npm:^7.2.0"
+ strip-ansi: "npm:^7.1.0"
+ checksum: 10c0/996a81a9e997481339de3a7996c56131ea292c0a0e9e42d1cd454e2390f1ce7015ec925dcdd29e3d74dc5d037a4aa1877e575b491555507bcd9f219df760a63f
+ languageName: node
+ linkType: hard
+
"ox@npm:0.1.2":
version: 0.1.2
resolution: "ox@npm:0.1.2"
@@ -8660,6 +9485,24 @@ __metadata:
languageName: node
linkType: hard
+"parse-json@npm:^8.0.0":
+ version: 8.1.0
+ resolution: "parse-json@npm:8.1.0"
+ dependencies:
+ "@babel/code-frame": "npm:^7.22.13"
+ index-to-position: "npm:^0.1.2"
+ type-fest: "npm:^4.7.1"
+ checksum: 10c0/39a49acafc1c41a763df2599a826eb77873a44b098a5f2ba548843229b334a16ff9d613d0381328e58031b0afaabc18ed2a01337a6522911ac7a81828df58bcb
+ languageName: node
+ linkType: hard
+
+"parse-ms@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "parse-ms@npm:4.0.0"
+ checksum: 10c0/a7900f4f1ebac24cbf5e9708c16fb2fd482517fad353aecd7aefb8c2ba2f85ce017913ccb8925d231770404780df46244ea6fec598b3bde6490882358b4d2d16
+ languageName: node
+ linkType: hard
+
"path-exists@npm:^4.0.0":
version: 4.0.0
resolution: "path-exists@npm:4.0.0"
@@ -8799,6 +9642,13 @@ __metadata:
languageName: node
linkType: hard
+"pirates@npm:^4.0.1":
+ version: 4.0.6
+ resolution: "pirates@npm:4.0.6"
+ checksum: 10c0/00d5fa51f8dded94d7429700fb91a0c1ead00ae2c7fd27089f0c5b63e6eca36197fe46384631872690a66f390c5e27198e99006ab77ae472692ab9c2ca903f36
+ languageName: node
+ linkType: hard
+
"pkg-types@npm:^1.0.3, pkg-types@npm:^1.2.1":
version: 1.2.1
resolution: "pkg-types@npm:1.2.1"
@@ -8826,6 +9676,37 @@ __metadata:
languageName: node
linkType: hard
+"polkadot-api@npm:^1.7.3":
+ version: 1.7.3
+ resolution: "polkadot-api@npm:1.7.3"
+ dependencies:
+ "@polkadot-api/cli": "npm:0.9.17"
+ "@polkadot-api/ink-contracts": "npm:0.2.0"
+ "@polkadot-api/json-rpc-provider": "npm:0.0.4"
+ "@polkadot-api/known-chains": "npm:0.5.6"
+ "@polkadot-api/logs-provider": "npm:0.0.6"
+ "@polkadot-api/metadata-builders": "npm:0.9.1"
+ "@polkadot-api/metadata-compatibility": "npm:0.1.11"
+ "@polkadot-api/observable-client": "npm:0.6.2"
+ "@polkadot-api/pjs-signer": "npm:0.6.0"
+ "@polkadot-api/polkadot-sdk-compat": "npm:2.3.1"
+ "@polkadot-api/polkadot-signer": "npm:0.1.6"
+ "@polkadot-api/signer": "npm:0.1.10"
+ "@polkadot-api/sm-provider": "npm:0.1.5"
+ "@polkadot-api/smoldot": "npm:0.3.5"
+ "@polkadot-api/substrate-bindings": "npm:0.9.3"
+ "@polkadot-api/substrate-client": "npm:0.3.0"
+ "@polkadot-api/utils": "npm:0.1.2"
+ "@polkadot-api/ws-provider": "npm:0.3.4"
+ peerDependencies:
+ rxjs: ">=7.8.0"
+ bin:
+ papi: bin/cli.mjs
+ polkadot-api: bin/cli.mjs
+ checksum: 10c0/ac430cd00d51308f65f3f8a1d7b405d3d1d86726c47481dfa2cfb2c08c36dda3cb51f0a880a00c7fa677e84bae3385de91e3da6627492fad89848b5a3e94b6fa
+ languageName: node
+ linkType: hard
+
"polkadot-staking-dashboard@workspace:.":
version: 0.0.0-use.local
resolution: "polkadot-staking-dashboard@workspace:."
@@ -8874,6 +9755,29 @@ __metadata:
languageName: node
linkType: hard
+"postcss-load-config@npm:^6.0.1":
+ version: 6.0.1
+ resolution: "postcss-load-config@npm:6.0.1"
+ dependencies:
+ lilconfig: "npm:^3.1.1"
+ peerDependencies:
+ jiti: ">=1.21.0"
+ postcss: ">=8.0.9"
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ postcss:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+ checksum: 10c0/74173a58816dac84e44853f7afbd283f4ef13ca0b6baeba27701214beec33f9e309b128f8102e2b173e8d45ecba45d279a9be94b46bf48d219626aa9b5730848
+ languageName: node
+ linkType: hard
+
"postcss-value-parser@npm:^4.0.2":
version: 4.2.0
resolution: "postcss-value-parser@npm:4.2.0"
@@ -8960,6 +9864,15 @@ __metadata:
languageName: node
linkType: hard
+"pretty-ms@npm:^9.0.0":
+ version: 9.1.0
+ resolution: "pretty-ms@npm:9.1.0"
+ dependencies:
+ parse-ms: "npm:^4.0.0"
+ checksum: 10c0/fd111aad8800a04dfd654e6016da69bdaa6fc6a4c280f8e727cffd8b5960558e94942f1a94d4aa6e4d179561a0fbb0366a9ebe0ccefbbb0f8ff853b129cdefb9
+ languageName: node
+ linkType: hard
+
"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0":
version: 4.2.0
resolution: "proc-log@npm:4.2.0"
@@ -9300,6 +10213,19 @@ __metadata:
languageName: node
linkType: hard
+"read-pkg@npm:^9.0.1":
+ version: 9.0.1
+ resolution: "read-pkg@npm:9.0.1"
+ dependencies:
+ "@types/normalize-package-data": "npm:^2.4.3"
+ normalize-package-data: "npm:^6.0.0"
+ parse-json: "npm:^8.0.0"
+ type-fest: "npm:^4.6.0"
+ unicorn-magic: "npm:^0.1.0"
+ checksum: 10c0/f3e27549dcdb18335597f4125a3d093a40ab0a18c16a6929a1575360ed5d8679b709b4a672730d9abf6aa8537a7f02bae0b4b38626f99409255acbd8f72f9964
+ languageName: node
+ linkType: hard
+
"readable-stream@npm:^2.3.3":
version: 2.3.8
resolution: "readable-stream@npm:2.3.8"
@@ -9339,6 +10265,13 @@ __metadata:
languageName: node
linkType: hard
+"readdirp@npm:^4.0.1":
+ version: 4.0.2
+ resolution: "readdirp@npm:4.0.2"
+ checksum: 10c0/a16ecd8ef3286dcd90648c3b103e3826db2b766cdb4a988752c43a83f683d01c7059158d623cbcd8bdfb39e65d302d285be2d208e7d9f34d022d912b929217dd
+ languageName: node
+ linkType: hard
+
"readdirp@npm:~3.6.0":
version: 3.6.0
resolution: "readdirp@npm:3.6.0"
@@ -9425,6 +10358,13 @@ __metadata:
languageName: node
linkType: hard
+"resolve-from@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "resolve-from@npm:5.0.0"
+ checksum: 10c0/b21cb7f1fb746de8107b9febab60095187781137fd803e6a59a76d421444b1531b641bba5857f5dc011974d8a5c635d61cec49e6bd3b7fc20e01f0fafc4efbf2
+ languageName: node
+ linkType: hard
+
"resolve-pkg-maps@npm:^1.0.0":
version: 1.0.0
resolution: "resolve-pkg-maps@npm:1.0.0"
@@ -9491,6 +10431,16 @@ __metadata:
languageName: node
linkType: hard
+"restore-cursor@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "restore-cursor@npm:5.1.0"
+ dependencies:
+ onetime: "npm:^7.0.0"
+ signal-exit: "npm:^4.1.0"
+ checksum: 10c0/c2ba89131eea791d1b25205bdfdc86699767e2b88dee2a590b1a6caa51737deac8bad0260a5ded2f7c074b7db2f3a626bcf1fcf3cdf35974cbeea5e2e6764f60
+ languageName: node
+ linkType: hard
+
"retry@npm:^0.12.0":
version: 0.12.0
resolution: "retry@npm:0.12.0"
@@ -9549,7 +10499,7 @@ __metadata:
languageName: node
linkType: hard
-"rollup@npm:^4.20.0":
+"rollup@npm:^4.20.0, rollup@npm:^4.24.0":
version: 4.26.0
resolution: "rollup@npm:4.26.0"
dependencies:
@@ -9956,6 +10906,15 @@ __metadata:
languageName: node
linkType: hard
+"smoldot@npm:2.0.31":
+ version: 2.0.31
+ resolution: "smoldot@npm:2.0.31"
+ dependencies:
+ ws: "npm:^8.8.1"
+ checksum: 10c0/610bf1ae1a80e7f682af144e2d0088e4d49949089c7b8bc29961ec112e120af78b7bf181718ad5f923cfca69d6b5ce23894ab10872dac6595ca1554277606977
+ languageName: node
+ linkType: hard
+
"snake-case@npm:^3.0.4":
version: 3.0.4
resolution: "snake-case@npm:3.0.4"
@@ -10018,6 +10977,15 @@ __metadata:
languageName: node
linkType: hard
+"sort-keys@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "sort-keys@npm:5.1.0"
+ dependencies:
+ is-plain-obj: "npm:^4.0.0"
+ checksum: 10c0/fdb7aeb02368ad91b2ea947b59f3c95d80f8c71bbcb5741ebd55852994f54a129af3b3663b280951566fe5897de056428810dbb58c61db831e588c0ac110f2b0
+ languageName: node
+ linkType: hard
+
"source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.2.0, source-map-js@npm:^1.2.1":
version: 1.2.1
resolution: "source-map-js@npm:1.2.1"
@@ -10032,6 +11000,15 @@ __metadata:
languageName: node
linkType: hard
+"source-map@npm:0.8.0-beta.0":
+ version: 0.8.0-beta.0
+ resolution: "source-map@npm:0.8.0-beta.0"
+ dependencies:
+ whatwg-url: "npm:^7.0.0"
+ checksum: 10c0/fb4d9bde9a9fdb2c29b10e5eae6c71d10e09ef467e1afb75fdec2eb7e11fa5b343a2af553f74f18b695dbc0b81f9da2e9fa3d7a317d5985e9939499ec6087835
+ languageName: node
+ linkType: hard
+
"source-map@npm:^0.7.4":
version: 0.7.4
resolution: "source-map@npm:0.7.4"
@@ -10039,6 +11016,40 @@ __metadata:
languageName: node
linkType: hard
+"spdx-correct@npm:^3.0.0":
+ version: 3.2.0
+ resolution: "spdx-correct@npm:3.2.0"
+ dependencies:
+ spdx-expression-parse: "npm:^3.0.0"
+ spdx-license-ids: "npm:^3.0.0"
+ checksum: 10c0/49208f008618b9119208b0dadc9208a3a55053f4fd6a0ae8116861bd22696fc50f4142a35ebfdb389e05ccf2de8ad142573fefc9e26f670522d899f7b2fe7386
+ languageName: node
+ linkType: hard
+
+"spdx-exceptions@npm:^2.1.0":
+ version: 2.5.0
+ resolution: "spdx-exceptions@npm:2.5.0"
+ checksum: 10c0/37217b7762ee0ea0d8b7d0c29fd48b7e4dfb94096b109d6255b589c561f57da93bf4e328c0290046115961b9209a8051ad9f525e48d433082fc79f496a4ea940
+ languageName: node
+ linkType: hard
+
+"spdx-expression-parse@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "spdx-expression-parse@npm:3.0.1"
+ dependencies:
+ spdx-exceptions: "npm:^2.1.0"
+ spdx-license-ids: "npm:^3.0.0"
+ checksum: 10c0/6f8a41c87759fa184a58713b86c6a8b028250f158159f1d03ed9d1b6ee4d9eefdc74181c8ddc581a341aa971c3e7b79e30b59c23b05d2436d5de1c30bdef7171
+ languageName: node
+ linkType: hard
+
+"spdx-license-ids@npm:^3.0.0":
+ version: 3.0.20
+ resolution: "spdx-license-ids@npm:3.0.20"
+ checksum: 10c0/bdff7534fad6ef59be49becda1edc3fb7f5b3d6f296a715516ab9d972b8ad59af2c34b2003e01db8970d4c673d185ff696ba74c6b61d3bf327e2b3eac22c297c
+ languageName: node
+ linkType: hard
+
"split-on-first@npm:^1.0.0":
version: 1.1.0
resolution: "split-on-first@npm:1.1.0"
@@ -10120,6 +11131,13 @@ __metadata:
languageName: node
linkType: hard
+"stdin-discarder@npm:^0.2.2":
+ version: 0.2.2
+ resolution: "stdin-discarder@npm:0.2.2"
+ checksum: 10c0/c78375e82e956d7a64be6e63c809c7f058f5303efcaf62ea48350af072bacdb99c06cba39209b45a071c1acbd49116af30df1df9abb448df78a6005b72f10537
+ languageName: node
+ linkType: hard
+
"stream-shift@npm:^1.0.2":
version: 1.0.3
resolution: "stream-shift@npm:1.0.3"
@@ -10156,6 +11174,17 @@ __metadata:
languageName: node
linkType: hard
+"string-width@npm:^7.2.0":
+ version: 7.2.0
+ resolution: "string-width@npm:7.2.0"
+ dependencies:
+ emoji-regex: "npm:^10.3.0"
+ get-east-asian-width: "npm:^1.0.0"
+ strip-ansi: "npm:^7.1.0"
+ checksum: 10c0/eb0430dd43f3199c7a46dcbf7a0b34539c76fe3aa62763d0b0655acdcbdf360b3f66f3d58ca25ba0205f42ea3491fa00f09426d3b7d3040e506878fc7664c9b9
+ languageName: node
+ linkType: hard
+
"string.prototype.matchall@npm:^4.0.11":
version: 4.0.11
resolution: "string.prototype.matchall@npm:4.0.11"
@@ -10247,7 +11276,7 @@ __metadata:
languageName: node
linkType: hard
-"strip-ansi@npm:^7.0.1":
+"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0":
version: 7.1.0
resolution: "strip-ansi@npm:7.1.0"
dependencies:
@@ -10270,6 +11299,13 @@ __metadata:
languageName: node
linkType: hard
+"strip-final-newline@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "strip-final-newline@npm:4.0.0"
+ checksum: 10c0/b0cf2b62d597a1b0e3ebc42b88767f0a0d45601f89fd379a928a1812c8779440c81abba708082c946445af1d6b62d5f16e2a7cf4f30d9d6587b89425fae801ff
+ languageName: node
+ linkType: hard
+
"strip-json-comments@npm:^3.1.1":
version: 3.1.1
resolution: "strip-json-comments@npm:3.1.1"
@@ -10321,6 +11357,24 @@ __metadata:
languageName: node
linkType: hard
+"sucrase@npm:^3.35.0":
+ version: 3.35.0
+ resolution: "sucrase@npm:3.35.0"
+ dependencies:
+ "@jridgewell/gen-mapping": "npm:^0.3.2"
+ commander: "npm:^4.0.0"
+ glob: "npm:^10.3.10"
+ lines-and-columns: "npm:^1.1.6"
+ mz: "npm:^2.7.0"
+ pirates: "npm:^4.0.1"
+ ts-interface-checker: "npm:^0.1.9"
+ bin:
+ sucrase: bin/sucrase
+ sucrase-node: bin/sucrase-node
+ checksum: 10c0/ac85f3359d2c2ecbf5febca6a24ae9bf96c931f05fde533c22a94f59c6a74895e5d5f0e871878dfd59c2697a75ebb04e4b2224ef0bfc24ca1210735c2ec191ef
+ languageName: node
+ linkType: hard
+
"superstruct@npm:^1.0.3":
version: 1.0.4
resolution: "superstruct@npm:1.0.4"
@@ -10403,6 +11457,24 @@ __metadata:
languageName: node
linkType: hard
+"thenify-all@npm:^1.0.0":
+ version: 1.6.0
+ resolution: "thenify-all@npm:1.6.0"
+ dependencies:
+ thenify: "npm:>= 3.1.0 < 4"
+ checksum: 10c0/9b896a22735e8122754fe70f1d65f7ee691c1d70b1f116fda04fea103d0f9b356e3676cb789506e3909ae0486a79a476e4914b0f92472c2e093d206aed4b7d6b
+ languageName: node
+ linkType: hard
+
+"thenify@npm:>= 3.1.0 < 4":
+ version: 3.3.1
+ resolution: "thenify@npm:3.3.1"
+ dependencies:
+ any-promise: "npm:^1.0.0"
+ checksum: 10c0/f375aeb2b05c100a456a30bc3ed07ef03a39cbdefe02e0403fb714b8c7e57eeaad1a2f5c4ecfb9ce554ce3db9c2b024eba144843cd9e344566d9fcee73b04767
+ languageName: node
+ linkType: hard
+
"thread-stream@npm:^0.15.1":
version: 0.15.2
resolution: "thread-stream@npm:0.15.2"
@@ -10426,6 +11498,23 @@ __metadata:
languageName: node
linkType: hard
+"tinyexec@npm:^0.3.1":
+ version: 0.3.1
+ resolution: "tinyexec@npm:0.3.1"
+ checksum: 10c0/11e7a7c5d8b3bddf8b5cbe82a9290d70a6fad84d528421d5d18297f165723cb53d2e737d8f58dcce5ca56f2e4aa2d060f02510b1f8971784f97eb3e9aec28f09
+ languageName: node
+ linkType: hard
+
+"tinyglobby@npm:^0.2.9":
+ version: 0.2.10
+ resolution: "tinyglobby@npm:0.2.10"
+ dependencies:
+ fdir: "npm:^6.4.2"
+ picomatch: "npm:^4.0.2"
+ checksum: 10c0/ce946135d39b8c0e394e488ad59f4092e8c4ecd675ef1bcd4585c47de1b325e61ec6adfbfbe20c3c2bfa6fd674c5b06de2a2e65c433f752ae170aff11793e5ef
+ languageName: node
+ linkType: hard
+
"tinypool@npm:^0.8.3":
version: 0.8.4
resolution: "tinypool@npm:0.8.4"
@@ -10456,6 +11545,15 @@ __metadata:
languageName: node
linkType: hard
+"tr46@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "tr46@npm:1.0.1"
+ dependencies:
+ punycode: "npm:^2.1.0"
+ checksum: 10c0/41525c2ccce86e3ef30af6fa5e1464e6d8bb4286a58ea8db09228f598889581ef62347153f6636cd41553dc41685bdfad0a9d032ef58df9fbb0792b3447d0f04
+ languageName: node
+ linkType: hard
+
"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
@@ -10463,6 +11561,15 @@ __metadata:
languageName: node
linkType: hard
+"tree-kill@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "tree-kill@npm:1.2.2"
+ bin:
+ tree-kill: cli.js
+ checksum: 10c0/7b1b7c7f17608a8f8d20a162e7957ac1ef6cd1636db1aba92f4e072dc31818c2ff0efac1e3d91064ede67ed5dc57c565420531a8134090a12ac10cf792ab14d2
+ languageName: node
+ linkType: hard
+
"ts-api-utils@npm:^1.3.0":
version: 1.4.0
resolution: "ts-api-utils@npm:1.4.0"
@@ -10472,6 +11579,13 @@ __metadata:
languageName: node
linkType: hard
+"ts-interface-checker@npm:^0.1.9":
+ version: 0.1.13
+ resolution: "ts-interface-checker@npm:0.1.13"
+ checksum: 10c0/232509f1b84192d07b81d1e9b9677088e590ac1303436da1e92b296e9be8e31ea042e3e1fd3d29b1742ad2c959e95afe30f63117b8f1bc3a3850070a5142fea7
+ languageName: node
+ linkType: hard
+
"ts-invariant@npm:^0.10.3":
version: 0.10.3
resolution: "ts-invariant@npm:0.10.3"
@@ -10481,6 +11595,15 @@ __metadata:
languageName: node
linkType: hard
+"tsc-prog@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "tsc-prog@npm:2.3.0"
+ peerDependencies:
+ typescript: ">=4"
+ checksum: 10c0/ca0ee722557e7974a221d6b3fa28dcbcc5e98b7bce9402bf113eae7c835d59644d24b48ac65d15c7f8dbe8cab61c54c4b0b2d252212c72bc4d09ce1fe8fbc937
+ languageName: node
+ linkType: hard
+
"tsconfck@npm:^3.0.3":
version: 3.1.4
resolution: "tsconfck@npm:3.1.4"
@@ -10528,6 +11651,47 @@ __metadata:
languageName: node
linkType: hard
+"tsup@npm:^8.2.4":
+ version: 8.3.5
+ resolution: "tsup@npm:8.3.5"
+ dependencies:
+ bundle-require: "npm:^5.0.0"
+ cac: "npm:^6.7.14"
+ chokidar: "npm:^4.0.1"
+ consola: "npm:^3.2.3"
+ debug: "npm:^4.3.7"
+ esbuild: "npm:^0.24.0"
+ joycon: "npm:^3.1.1"
+ picocolors: "npm:^1.1.1"
+ postcss-load-config: "npm:^6.0.1"
+ resolve-from: "npm:^5.0.0"
+ rollup: "npm:^4.24.0"
+ source-map: "npm:0.8.0-beta.0"
+ sucrase: "npm:^3.35.0"
+ tinyexec: "npm:^0.3.1"
+ tinyglobby: "npm:^0.2.9"
+ tree-kill: "npm:^1.2.2"
+ peerDependencies:
+ "@microsoft/api-extractor": ^7.36.0
+ "@swc/core": ^1
+ postcss: ^8.4.12
+ typescript: ">=4.5.0"
+ peerDependenciesMeta:
+ "@microsoft/api-extractor":
+ optional: true
+ "@swc/core":
+ optional: true
+ postcss:
+ optional: true
+ typescript:
+ optional: true
+ bin:
+ tsup: dist/cli-default.js
+ tsup-node: dist/cli-node.js
+ checksum: 10c0/7794953cbc784b7c8f14c4898d36a293b815b528d3098c2416aeaa2b4775dc477132cd12f75f6d32737dfd15ba10139c73f7039045352f2ba1ea7e5fe6fe3773
+ languageName: node
+ linkType: hard
+
"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
version: 0.4.0
resolution: "type-check@npm:0.4.0"
@@ -10558,6 +11722,13 @@ __metadata:
languageName: node
linkType: hard
+"type-fest@npm:^4.23.0, type-fest@npm:^4.6.0, type-fest@npm:^4.7.1":
+ version: 4.26.1
+ resolution: "type-fest@npm:4.26.1"
+ checksum: 10c0/d2719ff8d380befe8a3c61068f37f28d6fa2849fd140c5d2f0f143099e371da6856aad7c97e56b83329d45bfe504afe9fd936a7cff600cc0d46aa9ffb008d6c6
+ languageName: node
+ linkType: hard
+
"typed-array-buffer@npm:^1.0.2":
version: 1.0.2
resolution: "typed-array-buffer@npm:1.0.2"
@@ -10610,7 +11781,7 @@ __metadata:
languageName: node
linkType: hard
-"typescript@npm:^5.4.3":
+"typescript@npm:^5.4.3, typescript@npm:^5.5.4":
version: 5.6.3
resolution: "typescript@npm:5.6.3"
bin:
@@ -10620,7 +11791,7 @@ __metadata:
languageName: node
linkType: hard
-"typescript@patch:typescript@npm%3A^5.4.3#optional!builtin":
+"typescript@patch:typescript@npm%3A^5.4.3#optional!builtin, typescript@patch:typescript@npm%3A^5.5.4#optional!builtin":
version: 5.6.3
resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=5adc0c"
bin:
@@ -10714,6 +11885,20 @@ __metadata:
languageName: node
linkType: hard
+"unicorn-magic@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "unicorn-magic@npm:0.1.0"
+ checksum: 10c0/e4ed0de05b0a05e735c7d8a2930881e5efcfc3ec897204d5d33e7e6247f4c31eac92e383a15d9a6bccb7319b4271ee4bea946e211bf14951fec6ff2cbbb66a92
+ languageName: node
+ linkType: hard
+
+"unicorn-magic@npm:^0.3.0":
+ version: 0.3.0
+ resolution: "unicorn-magic@npm:0.3.0"
+ checksum: 10c0/0a32a997d6c15f1c2a077a15b1c4ca6f268d574cf5b8975e778bb98e6f8db4ef4e86dfcae4e158cd4c7e38fb4dd383b93b13eefddc7f178dea13d3ac8a603271
+ languageName: node
+ linkType: hard
+
"unique-filename@npm:^3.0.0":
version: 3.0.0
resolution: "unique-filename@npm:3.0.0"
@@ -10916,6 +12101,16 @@ __metadata:
languageName: node
linkType: hard
+"validate-npm-package-license@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "validate-npm-package-license@npm:3.0.4"
+ dependencies:
+ spdx-correct: "npm:^3.0.0"
+ spdx-expression-parse: "npm:^3.0.0"
+ checksum: 10c0/7b91e455a8de9a0beaa9fe961e536b677da7f48c9a493edf4d4d4a87fd80a7a10267d438723364e432c2fcd00b5650b5378275cded362383ef570276e6312f4f
+ languageName: node
+ linkType: hard
+
"valtio@npm:1.11.2":
version: 1.11.2
resolution: "valtio@npm:1.11.2"
@@ -11307,6 +12502,13 @@ __metadata:
languageName: node
linkType: hard
+"webidl-conversions@npm:^4.0.2":
+ version: 4.0.2
+ resolution: "webidl-conversions@npm:4.0.2"
+ checksum: 10c0/def5c5ac3479286dffcb604547628b2e6b46c5c5b8a8cfaa8c71dc3bafc85859bde5fbe89467ff861f571ab38987cf6ab3d6e7c80b39b999e50e803c12f3164f
+ languageName: node
+ linkType: hard
+
"whatwg-url@npm:^5.0.0":
version: 5.0.0
resolution: "whatwg-url@npm:5.0.0"
@@ -11317,6 +12519,17 @@ __metadata:
languageName: node
linkType: hard
+"whatwg-url@npm:^7.0.0":
+ version: 7.1.0
+ resolution: "whatwg-url@npm:7.1.0"
+ dependencies:
+ lodash.sortby: "npm:^4.7.0"
+ tr46: "npm:^1.0.1"
+ webidl-conversions: "npm:^4.0.2"
+ checksum: 10c0/2785fe4647690e5a0225a79509ba5e21fdf4a71f9de3eabdba1192483fe006fc79961198e0b99f82751557309f17fc5a07d4d83c251aa5b2f85ba71e674cbee9
+ languageName: node
+ linkType: hard
+
"which-boxed-primitive@npm:^1.0.2":
version: 1.0.2
resolution: "which-boxed-primitive@npm:1.0.2"
@@ -11463,6 +12676,41 @@ __metadata:
languageName: node
linkType: hard
+"write-file-atomic@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "write-file-atomic@npm:5.0.1"
+ dependencies:
+ imurmurhash: "npm:^0.1.4"
+ signal-exit: "npm:^4.0.1"
+ checksum: 10c0/e8c850a8e3e74eeadadb8ad23c9d9d63e4e792bd10f4836ed74189ef6e996763959f1249c5650e232f3c77c11169d239cbfc8342fc70f3fe401407d23810505d
+ languageName: node
+ linkType: hard
+
+"write-json-file@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "write-json-file@npm:6.0.0"
+ dependencies:
+ detect-indent: "npm:^7.0.1"
+ is-plain-obj: "npm:^4.1.0"
+ sort-keys: "npm:^5.0.0"
+ write-file-atomic: "npm:^5.0.1"
+ checksum: 10c0/3f8f0caec7948d696b1e898512547bba7b63e99eb5b67ddb74cd9ea02aa0b88d48f5b710be3b26ac3ffa8c3e58c779bd610fb349d3cec6e8fb621596a8f85069
+ languageName: node
+ linkType: hard
+
+"write-package@npm:^7.1.0":
+ version: 7.1.0
+ resolution: "write-package@npm:7.1.0"
+ dependencies:
+ deepmerge-ts: "npm:^7.1.0"
+ read-pkg: "npm:^9.0.1"
+ sort-keys: "npm:^5.0.0"
+ type-fest: "npm:^4.23.0"
+ write-json-file: "npm:^6.0.0"
+ checksum: 10c0/0db9ca588fc00c753409633ce7777eae4147c6b60993643399f4af0e0ce672b5943587ff5269c3adda36090065d0ef1cf2c6936a62e0d1a548dc81c6507f4f2a
+ languageName: node
+ linkType: hard
+
"ws@npm:8.18.0, ws@npm:^8.15.1, ws@npm:^8.18.0, ws@npm:^8.8.1":
version: 8.18.0
resolution: "ws@npm:8.18.0"
@@ -11629,6 +12877,13 @@ __metadata:
languageName: node
linkType: hard
+"yoctocolors@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "yoctocolors@npm:2.1.1"
+ checksum: 10c0/85903f7fa96f1c70badee94789fade709f9d83dab2ec92753d612d84fcea6d34c772337a9f8914c6bed2f5fc03a428ac5d893e76fab636da5f1236ab725486d0
+ languageName: node
+ linkType: hard
+
"zen-observable-ts@npm:^1.2.5":
version: 1.2.5
resolution: "zen-observable-ts@npm:1.2.5"
From 65bf7ad55abde39ffd4d6a30e06584a4caaf855e Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 14 Nov 2024 19:12:31 +0700
Subject: [PATCH 02/84] expose untyped api
---
packages/app/src/contexts/Api/index.tsx | 9 ++++++++-
packages/app/src/model/Api/index.ts | 12 +++++++++++-
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 8ffa019c9..dd9c2c87e 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -226,7 +226,7 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
SubscriptionsController.set(network, 'activeEra', new ActiveEra(network));
};
- const handlePapiReady = (e: Event) => {
+ const handlePapiReady = async (e: Event) => {
if (isCustomEvent(e)) {
const { chainType, genesisHash, ss58Format, tokenDecimals, tokenSymbol } =
e.detail;
@@ -241,7 +241,14 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
};
setChainSpecs({ ...newChainSpecs, received: true });
+ const apiInstance = ApiController.get(network);
+ const pApi = apiInstance.papiApi;
+
// TODO: set consts from here.
+ console.log(
+ 'bonding duration: ',
+ await pApi.constants.Staking.BondingDuration()
+ );
}
}
};
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index e4dee3a01..642c421a4 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -16,7 +16,7 @@ import { SubscriptionsController } from 'controllers/Subscriptions';
import { ScProvider } from '@polkadot/rpc-provider/substrate-connect';
import { WellKnownChain } from '@substrate/connect';
import * as Sc from '@substrate/connect';
-import type { PolkadotClient } from 'polkadot-api';
+import type { PolkadotClient, UnsafeApi } from 'polkadot-api';
import { createClient } from 'polkadot-api';
import { getWsProvider } from 'polkadot-api/ws-provider/web';
import { getSmProvider } from 'polkadot-api/sm-provider';
@@ -37,6 +37,9 @@ export class Api {
// PAPI Instance.
#papiClient: PolkadotClient;
+ // PAPI API.
+ #papiApi: UnsafeApi;
+
// PAPI Chain Spec.
#papiChainSpec: PapiChainSpec;
@@ -57,6 +60,10 @@ export class Api {
return this.#papiClient;
}
+ get papiApi() {
+ return this.#papiApi;
+ }
+
get papiChainSpec() {
return this.#papiChainSpec;
}
@@ -104,6 +111,9 @@ export class Api {
// Wait for api to be ready.
await this.#api.isReady;
+ // Initialise PAPI API.
+ this.#papiApi = this.#papiClient.getUnsafeApi();
+
// Fetch chain spec and metadata from PAPI client.
await this.fetchChainSpec();
} catch (e) {
From e3f2cbc93ab0b5eb17a93ced7e4e403fa67f179f Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 14 Nov 2024 19:19:22 +0700
Subject: [PATCH 03/84] destroy on disconnect
---
packages/app/src/contexts/Api/index.tsx | 2 +-
packages/app/src/model/Api/index.ts | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index dd9c2c87e..de563126d 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -486,7 +486,7 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
reInitialiseApi(connectionType);
}, [network]);
- // Call `unsubscribe` on active instnace on unmount.
+ // Call `unsubscribe` on active instance on unmount.
useEffect(
() => () => {
const instance = ApiController.get(network);
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index 642c421a4..b95319024 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -280,6 +280,9 @@ export class Api {
await this.#provider?.disconnect();
await this.#api?.disconnect();
+ // Disconnect from PAPI Client.
+ this.#papiClient?.destroy();
+
// Tell UI Api is destroyed.
if (destroy) {
// NOTE: destroyed event is not currently in use.
From 2eb64547d5dd544c34fdd2a5e0fdcba2a71bfb2e Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 09:22:24 +0700
Subject: [PATCH 04/84] consts to papi
---
packages/app/src/contexts/Api/index.tsx | 70 +++++++++++++----
packages/app/src/model/Api/index.ts | 21 +++++
.../src/model/Query/StakingConstants/index.ts | 76 -------------------
3 files changed, 78 insertions(+), 89 deletions(-)
delete mode 100644 packages/app/src/model/Query/StakingConstants/index.ts
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index de563126d..4b3de42b3 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -37,7 +37,6 @@ import type {
ApiStatus,
ConnectionType,
} from 'model/Api/types';
-import { StakingConstants } from 'model/Query/StakingConstants';
import { Era } from 'model/Query/Era';
import { NetworkMeta } from 'model/Query/NetworkMeta';
import { SubscriptionsController } from 'controllers/Subscriptions';
@@ -169,9 +168,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// 1. Fetch network data for bootstrapping app state:
- // Get general network constants for staking UI.
- const newConsts = await new StakingConstants().fetch(api, network);
-
// Get active and previous era.
const { activeEra: newActiveEra, previousEra } = await new Era().fetch(api);
@@ -184,7 +180,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// 2. Populate all config state:
- setConsts(newConsts);
setStateWithRef(newNetworkMetrics, setNetworkMetrics, networkMetricsRef);
const { index, start } = newActiveEra;
setStateWithRef({ index, start }, setActiveEra, activeEraRef);
@@ -239,16 +234,65 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
tokenSymbol,
received: true,
};
- setChainSpecs({ ...newChainSpecs, received: true });
- const apiInstance = ApiController.get(network);
- const pApi = apiInstance.papiApi;
-
- // TODO: set consts from here.
- console.log(
- 'bonding duration: ',
- await pApi.constants.Staking.BondingDuration()
+ const api = ApiController.get(network);
+ const bondingDuration = await api.getConstant(
+ 'Staking',
+ 'BondingDuration',
+ 0
+ );
+ const sessionsPerEra = await api.getConstant(
+ 'Staking',
+ 'SessionsPerEra',
+ 0
+ );
+ const maxExposurePageSize = await api.getConstant(
+ 'Staking',
+ 'MaxExposurePageSize',
+ 0
+ );
+ const historyDepth = await api.getConstant(
+ 'Staking',
+ 'HistoryDepth',
+ 0
+ );
+ const expectedBlockTime = await api.getConstant(
+ 'Babe',
+ 'ExpectedBlockTime',
+ 0
);
+ const epochDuration = await api.getConstant('Babe', 'EpochDuration', 0);
+ const existentialDeposit = await api.getConstant(
+ 'Balances',
+ 'ExistentialDeposit',
+ 0
+ );
+ const fastUnstakeDeposit = await api.getConstant(
+ 'FastUnstake',
+ 'Deposit',
+ 0
+ );
+ const poolsPalletId = await api.getConstant(
+ 'NominationPools',
+ 'PalletId',
+ new Uint8Array(0),
+ 'asBytes'
+ );
+
+ setChainSpecs({ ...newChainSpecs, received: true });
+
+ setConsts({
+ maxNominations: new BigNumber(16),
+ bondDuration: new BigNumber(bondingDuration),
+ sessionsPerEra: new BigNumber(sessionsPerEra),
+ maxExposurePageSize: new BigNumber(maxExposurePageSize),
+ historyDepth: new BigNumber(historyDepth),
+ expectedBlockTime: new BigNumber(expectedBlockTime.toString()),
+ epochDuration: new BigNumber(epochDuration.toString()),
+ existentialDeposit: new BigNumber(existentialDeposit.toString()),
+ fastUnstakeDeposit: new BigNumber(fastUnstakeDeposit.toString()),
+ poolsPalletId,
+ });
}
}
};
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index b95319024..b0018d5fa 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -196,6 +196,27 @@ export class Api {
}
}
+ // Get a pallet constant, with a fallback value.
+ getConstant = async (
+ pallet: string,
+ key: string,
+ fallback: T,
+ formatter?: 'asBytes'
+ ): Promise => {
+ try {
+ const result = await this.#papiApi.constants[pallet][key]();
+
+ switch (formatter) {
+ case 'asBytes':
+ return result.asBytes();
+ default:
+ return result;
+ }
+ } catch (e) {
+ return fallback;
+ }
+ };
+
// Handler for dispatching `papi-ready` events.
dispatchPapiReadyEvent() {
const detail: PapiReadyEvent = {
diff --git a/packages/app/src/model/Query/StakingConstants/index.ts b/packages/app/src/model/Query/StakingConstants/index.ts
deleted file mode 100644
index e68ff841e..000000000
--- a/packages/app/src/model/Query/StakingConstants/index.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
-// SPDX-License-Identifier: GPL-3.0-only
-
-import type { ApiPromise } from '@polkadot/api';
-import BigNumber from 'bignumber.js';
-import { NetworkList } from 'config/networks';
-import { stringToBn } from 'library/Utils';
-
-export class StakingConstants {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
- // Network config fallback values.
- FALLBACK = {
- MAX_NOMINATIONS: new BigNumber(16),
- BONDING_DURATION: new BigNumber(28),
- SESSIONS_PER_ERA: new BigNumber(6),
- MAX_ELECTING_VOTERS: new BigNumber(22500),
- EXPECTED_BLOCK_TIME: new BigNumber(6000),
- EPOCH_DURATION: new BigNumber(2400),
- };
-
- // Fetch network constants.
- async fetch(api: ApiPromise, network: string) {
- const allPromises = [
- api.consts.staking.bondingDuration,
- api.consts.staking.maxNominations,
- api.consts.staking.sessionsPerEra,
- api.consts.electionProviderMultiPhase.maxElectingVoters,
- api.consts.babe.expectedBlockTime,
- api.consts.babe.epochDuration,
- api.consts.balances.existentialDeposit,
- api.consts.staking.historyDepth,
- api.consts.fastUnstake.deposit,
- api.consts.nominationPools.palletId,
- api.consts.staking.maxExposurePageSize,
- ];
-
- const consts = await Promise.all(allPromises);
-
- return {
- bondDuration: consts[0]
- ? stringToBn(consts[0].toString())
- : this.FALLBACK.BONDING_DURATION,
- maxNominations: consts[1]
- ? stringToBn(consts[1].toString())
- : this.FALLBACK.MAX_NOMINATIONS,
- sessionsPerEra: consts[2]
- ? stringToBn(consts[2].toString())
- : this.FALLBACK.SESSIONS_PER_ERA,
- maxElectingVoters: consts[3]
- ? stringToBn(consts[3].toString())
- : this.FALLBACK.MAX_ELECTING_VOTERS,
- expectedBlockTime: consts[4]
- ? stringToBn(consts[4].toString())
- : this.FALLBACK.EXPECTED_BLOCK_TIME,
- epochDuration: consts[5]
- ? stringToBn(consts[5].toString())
- : this.FALLBACK.EPOCH_DURATION,
- existentialDeposit: consts[6]
- ? stringToBn(consts[6].toString())
- : new BigNumber(0),
- historyDepth: consts[7]
- ? stringToBn(consts[7].toString())
- : new BigNumber(0),
- fastUnstakeDeposit: consts[8]
- ? stringToBn(consts[8].toString())
- : new BigNumber(0),
- poolsPalletId: consts[9] ? consts[9].toU8a() : new Uint8Array(0),
- maxExposurePageSize: consts[10]
- ? stringToBn(consts[10].toString())
- : NetworkList[network].maxExposurePageSize,
- };
- }
-}
From f64fb6c4f45719ec355e9331458ae8607ef4fb73 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 09:42:42 +0700
Subject: [PATCH 05/84] activeEra to papi
---
packages/app/src/contexts/Api/index.tsx | 5 ++++-
packages/app/src/model/Api/index.ts | 5 +++--
packages/app/src/model/Api/types.ts | 3 +++
packages/app/src/model/Query/Era/index.ts | 26 ++++++++++++++---------
4 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 4b3de42b3..4b0147ce5 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -165,11 +165,14 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
const bootstrapNetworkConfig = async () => {
const apiInstance = ApiController.get(network);
const api = apiInstance.api;
+ const pApi = apiInstance.papiApi;
// 1. Fetch network data for bootstrapping app state:
// Get active and previous era.
- const { activeEra: newActiveEra, previousEra } = await new Era().fetch(api);
+ const { activeEra: newActiveEra, previousEra } = await new Era().fetch(
+ pApi
+ );
// Get network meta data related to staking and pools.
const {
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index b0018d5fa..4b3ac6a0d 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -9,6 +9,7 @@ import type {
APIEventDetail,
ConnectionType,
EventApiStatus,
+ PapiApi,
PapiChainSpec,
PapiReadyEvent,
} from './types';
@@ -16,7 +17,7 @@ import { SubscriptionsController } from 'controllers/Subscriptions';
import { ScProvider } from '@polkadot/rpc-provider/substrate-connect';
import { WellKnownChain } from '@substrate/connect';
import * as Sc from '@substrate/connect';
-import type { PolkadotClient, UnsafeApi } from 'polkadot-api';
+import type { PolkadotClient } from 'polkadot-api';
import { createClient } from 'polkadot-api';
import { getWsProvider } from 'polkadot-api/ws-provider/web';
import { getSmProvider } from 'polkadot-api/sm-provider';
@@ -38,7 +39,7 @@ export class Api {
#papiClient: PolkadotClient;
// PAPI API.
- #papiApi: UnsafeApi;
+ #papiApi: PapiApi;
// PAPI Chain Spec.
#papiChainSpec: PapiChainSpec;
diff --git a/packages/app/src/model/Api/types.ts b/packages/app/src/model/Api/types.ts
index eebef4ff4..eaae0bf6f 100644
--- a/packages/app/src/model/Api/types.ts
+++ b/packages/app/src/model/Api/types.ts
@@ -1,6 +1,7 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
+import type { UnsafeApi } from 'polkadot-api';
import type { NetworkName, SystemChainId } from 'types';
export interface APIConfig {
@@ -28,6 +29,8 @@ export type PapiReadyEvent = PapiChainSpec & {
chainType: string;
};
+export type PapiApi = UnsafeApi;
+
export type ConnectionType = 'ws' | 'sc';
export type ApiStatus = 'connecting' | 'connected' | 'disconnected' | 'ready';
diff --git a/packages/app/src/model/Query/Era/index.ts b/packages/app/src/model/Query/Era/index.ts
index 875984527..fb83230c7 100644
--- a/packages/app/src/model/Query/Era/index.ts
+++ b/packages/app/src/model/Query/Era/index.ts
@@ -1,21 +1,27 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { ApiPromise } from '@polkadot/api';
import BigNumber from 'bignumber.js';
-import type { AnyApi } from 'types';
+import type { PapiApi } from 'model/Api/types';
export class Era {
// Fetch network constants.
- async fetch(api: ApiPromise) {
- // Fetch the active era.
- const result = JSON.parse(
- ((await api.query.staking.activeEra()) as AnyApi)
- .unwrapOrDefault()
- .toString()
- );
+ async fetch(api: PapiApi) {
+ let result;
+ try {
+ const { index, start } = await api.query.Staking.ActiveEra.getValue();
+ result = {
+ start,
+ index,
+ };
+ } catch (e) {
+ result = {
+ start: 0,
+ index: 0,
+ };
+ }
- // Store active era.
+ // Store active era as BigNumbers.
const activeEra = {
index: new BigNumber(result.index),
start: new BigNumber(result.start),
From 6e2e58fdb2894e62846cc16feec476bef243cecf Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:03:32 +0700
Subject: [PATCH 06/84] NetworkMeta fetch to pApi
---
packages/app/src/contexts/Api/defaults.ts | 1 -
packages/app/src/contexts/Api/index.tsx | 3 +-
packages/app/src/contexts/Api/types.ts | 1 -
.../app/src/model/Query/NetworkMeta/index.ts | 150 ++++++++++--------
.../model/Subscribe/StakingMetrics/index.ts | 18 +--
.../src/pages/Overview/NetworkSats/index.tsx | 4 +-
6 files changed, 92 insertions(+), 85 deletions(-)
diff --git a/packages/app/src/contexts/Api/defaults.ts b/packages/app/src/contexts/Api/defaults.ts
index 8d647590e..40ebace65 100644
--- a/packages/app/src/contexts/Api/defaults.ts
+++ b/packages/app/src/contexts/Api/defaults.ts
@@ -71,7 +71,6 @@ export const defaultPoolsConfig: APIPoolsConfig = {
};
export const defaultStakingMetrics: APIStakingMetrics = {
- totalNominators: new BigNumber(0),
totalValidators: new BigNumber(0),
lastReward: new BigNumber(0),
lastTotalStake: new BigNumber(0),
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 4b0147ce5..1931cab23 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -164,7 +164,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// Bootstrap app-wide chain state.
const bootstrapNetworkConfig = async () => {
const apiInstance = ApiController.get(network);
- const api = apiInstance.api;
const pApi = apiInstance.papiApi;
// 1. Fetch network data for bootstrapping app state:
@@ -179,7 +178,7 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
networkMetrics: newNetworkMetrics,
poolsConfig: newPoolsConfig,
stakingMetrics: newStakingMetrics,
- } = await new NetworkMeta().fetch(api, newActiveEra, previousEra);
+ } = await new NetworkMeta().fetch(pApi, newActiveEra, previousEra);
// 2. Populate all config state:
diff --git a/packages/app/src/contexts/Api/types.ts b/packages/app/src/contexts/Api/types.ts
index 0420ed7f8..5dd28bc86 100644
--- a/packages/app/src/contexts/Api/types.ts
+++ b/packages/app/src/contexts/Api/types.ts
@@ -62,7 +62,6 @@ export interface APIPoolsConfig {
}
export interface APIStakingMetrics {
- totalNominators: BigNumber;
totalValidators: BigNumber;
lastReward: BigNumber;
lastTotalStake: BigNumber;
diff --git a/packages/app/src/model/Query/NetworkMeta/index.ts b/packages/app/src/model/Query/NetworkMeta/index.ts
index ae8839fff..b4e14211b 100644
--- a/packages/app/src/model/Query/NetworkMeta/index.ts
+++ b/packages/app/src/model/Query/NetworkMeta/index.ts
@@ -1,97 +1,109 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { ApiPromise } from '@polkadot/api';
-import { rmCommas } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import type { APIActiveEra } from 'contexts/Api/types';
import { stringToBn } from 'library/Utils';
+import type { PapiApi } from 'model/Api/types';
export class NetworkMeta {
// Fetch network constants.
- async fetch(
- api: ApiPromise,
- activeEra: APIActiveEra,
- previousEra: BigNumber
- ) {
- // Fetch network configuration.
- const networkMeta = await api.queryMulti([
- // Network metrics.
- api.query.balances.totalIssuance,
- api.query.auctions.auctionCounter,
- api.query.paraSessionInfo.earliestStoredSession,
- api.query.fastUnstake.erasToCheckPerBlock,
- api.query.staking.minimumActiveStake,
- // Nomination pool configs.
- api.query.nominationPools.counterForPoolMembers,
- api.query.nominationPools.counterForBondedPools,
- api.query.nominationPools.counterForRewardPools,
- api.query.nominationPools.lastPoolId,
- api.query.nominationPools.maxPoolMembers,
- api.query.nominationPools.maxPoolMembersPerPool,
- api.query.nominationPools.maxPools,
- api.query.nominationPools.minCreateBond,
- api.query.nominationPools.minJoinBond,
- api.query.nominationPools.globalMaxCommission,
- // Staking metrics.
- api.query.staking.counterForNominators,
- api.query.staking.counterForValidators,
- api.query.staking.maxValidatorsCount,
- api.query.staking.validatorCount,
- [api.query.staking.erasValidatorReward, previousEra.toString()],
- [api.query.staking.erasTotalStake, previousEra.toString()],
- api.query.staking.minNominatorBond,
- [api.query.staking.erasTotalStake, activeEra.index.toString()],
- api.query.staking.counterForNominators,
+ async fetch(pApi: PapiApi, activeEra: APIActiveEra, previousEra: BigNumber) {
+ const totalIssuance = await pApi.query.Balances.TotalIssuance.getValue();
+
+ const [
+ auctionCounter,
+ earliestStoredSession,
+ erasToCheckPerBlock,
+ minimumActiveStake,
+ counterForPoolMembers,
+ counterForBondedPools,
+ counterForRewardPools,
+ lastPoolId,
+ maxPoolMembersRaw,
+ maxPoolMembersPerPoolRaw,
+ maxPoolsRaw,
+ minCreateBond,
+ minJoinBond,
+ globalMaxCommission,
+ counterForNominators,
+ counterForValidators,
+ maxValidatorsCount,
+ validatorCount,
+ prevErasValidatorReward,
+ prevEraErasTotalStake,
+ minNominatorBond,
+ activeEraErasTotalStake,
+ ] = await Promise.all([
+ pApi.query.Auctions.AuctionCounter.getValue(),
+ pApi.query.ParaSessionInfo.EarliestStoredSession.getValue(),
+ pApi.query.FastUnstake.ErasToCheckPerBlock.getValue(),
+ pApi.query.Staking.MinimumActiveStake.getValue(),
+ pApi.query.NominationPools.CounterForPoolMembers.getValue(),
+ pApi.query.NominationPools.CounterForBondedPools.getValue(),
+ pApi.query.NominationPools.CounterForRewardPools.getValue(),
+ pApi.query.NominationPools.LastPoolId.getValue(),
+ pApi.query.NominationPools.MaxPoolMembers.getValue(),
+ pApi.query.NominationPools.MaxPoolMembersPerPool.getValue(),
+ pApi.query.NominationPools.MaxPools.getValue(),
+ pApi.query.NominationPools.MinCreateBond.getValue(),
+ pApi.query.NominationPools.MinJoinBond.getValue(),
+ pApi.query.NominationPools.GlobalMaxCommission.getValue(),
+ pApi.query.Staking.CounterForNominators.getValue(),
+ pApi.query.Staking.CounterForValidators.getValue(),
+ pApi.query.Staking.MaxValidatorsCount.getValue(),
+ pApi.query.Staking.ValidatorCount.getValue(),
+ pApi.query.Staking.ErasValidatorReward.getValue(previousEra.toString()),
+ pApi.query.Staking.ErasTotalStake.getValue(previousEra.toString()),
+ pApi.query.Staking.MinNominatorBond.getValue(),
+ pApi.query.Staking.ErasTotalStake.getValue(activeEra.index.toString()),
]);
- // format optional configs to BigNumber or null.
- const maxPoolMembers = networkMeta[9].toHuman()
- ? new BigNumber(rmCommas(networkMeta[9].toString()))
- : null;
+ // Format globalMaxCommission from a perbill to a percent.
+ const globalMaxCommissionAsPercent = BigInt(globalMaxCommission) / 1000000n;
- const maxPoolMembersPerPool = networkMeta[10].toHuman()
- ? new BigNumber(rmCommas(networkMeta[10].toString()))
+ // Format max pool members to be a BigNumber, or null if it's not set.
+ const maxPoolMembers = maxPoolMembersRaw
+ ? new BigNumber(maxPoolMembersRaw.toString())
: null;
- const maxPools = networkMeta[11].toHuman()
- ? new BigNumber(rmCommas(networkMeta[11].toString()))
+ // Format max pool members per pool to be a BigNumber, or null if it's not set.
+ const maxPoolMembersPerPool = maxPoolMembersPerPoolRaw
+ ? new BigNumber(maxPoolMembersPerPoolRaw.toString())
: null;
+ // Format max pools to be a BigNumber, or null if it's not set.
+ const maxPools = maxPoolsRaw ? new BigNumber(maxPoolsRaw.toString()) : null;
+
return {
networkMetrics: {
- totalIssuance: new BigNumber(networkMeta[0].toString()),
- auctionCounter: new BigNumber(networkMeta[1].toString()),
- earliestStoredSession: new BigNumber(networkMeta[2].toString()),
- fastUnstakeErasToCheckPerBlock: Number(
- rmCommas(networkMeta[3].toString())
- ),
- minimumActiveStake: new BigNumber(networkMeta[4].toString()),
+ totalIssuance: new BigNumber(totalIssuance.toString()),
+ auctionCounter: new BigNumber(auctionCounter.toString()),
+ earliestStoredSession: new BigNumber(earliestStoredSession.toString()),
+ fastUnstakeErasToCheckPerBlock: Number(erasToCheckPerBlock.toString()),
+ minimumActiveStake: new BigNumber(minimumActiveStake.toString()),
},
poolsConfig: {
- counterForPoolMembers: stringToBn(networkMeta[5].toString()),
- counterForBondedPools: stringToBn(networkMeta[6].toString()),
- counterForRewardPools: stringToBn(networkMeta[7].toString()),
- lastPoolId: stringToBn(networkMeta[8].toString()),
+ counterForPoolMembers: stringToBn(counterForPoolMembers.toString()),
+ counterForBondedPools: stringToBn(counterForBondedPools.toString()),
+ counterForRewardPools: stringToBn(counterForRewardPools.toString()),
+ lastPoolId: stringToBn(lastPoolId.toString()),
maxPoolMembers,
maxPoolMembersPerPool,
maxPools,
- minCreateBond: stringToBn(networkMeta[12].toString()),
- minJoinBond: stringToBn(networkMeta[13].toString()),
- globalMaxCommission: Number(
- String(networkMeta[14]?.toHuman() || '100%').slice(0, -1)
- ),
+ minCreateBond: stringToBn(minCreateBond.toString()),
+ minJoinBond: stringToBn(minJoinBond.toString()),
+ globalMaxCommission: Number(globalMaxCommissionAsPercent.toString()),
},
stakingMetrics: {
- totalNominators: stringToBn(networkMeta[15].toString()),
- totalValidators: stringToBn(networkMeta[16].toString()),
- maxValidatorsCount: stringToBn(networkMeta[17].toString()),
- validatorCount: stringToBn(networkMeta[18].toString()),
- lastReward: stringToBn(networkMeta[19].toString()),
- lastTotalStake: stringToBn(networkMeta[20].toString()),
- minNominatorBond: stringToBn(networkMeta[21].toString()),
- totalStaked: stringToBn(networkMeta[22].toString()),
- counterForNominators: stringToBn(networkMeta[23].toString()),
+ totalValidators: stringToBn(counterForValidators.toString()),
+ maxValidatorsCount: stringToBn(maxValidatorsCount.toString()),
+ validatorCount: stringToBn(validatorCount.toString()),
+ lastReward: stringToBn(prevErasValidatorReward.toString()),
+ lastTotalStake: stringToBn(prevEraErasTotalStake.toString()),
+ minNominatorBond: stringToBn(minNominatorBond.toString()),
+ totalStaked: stringToBn(activeEraErasTotalStake.toString()),
+ counterForNominators: stringToBn(counterForNominators.toString()),
},
};
}
diff --git a/packages/app/src/model/Subscribe/StakingMetrics/index.ts b/packages/app/src/model/Subscribe/StakingMetrics/index.ts
index c7ac0c5c3..e0032237c 100644
--- a/packages/app/src/model/Subscribe/StakingMetrics/index.ts
+++ b/packages/app/src/model/Subscribe/StakingMetrics/index.ts
@@ -52,7 +52,6 @@ export class StakingMetrics implements Unsubscribable {
if (api && this.#unsub === undefined) {
const unsub = await api.queryMulti(
[
- api.query.staking.counterForNominators,
api.query.staking.counterForValidators,
api.query.staking.maxValidatorsCount,
api.query.staking.validatorCount,
@@ -70,15 +69,14 @@ export class StakingMetrics implements Unsubscribable {
],
(result) => {
const stakingMetrics = {
- totalNominators: stringToBn(result[0].toString()),
- totalValidators: stringToBn(result[1].toString()),
- maxValidatorsCount: stringToBn(result[2].toString()),
- validatorCount: stringToBn(result[3].toString()),
- lastReward: stringToBn(result[4].toString()),
- lastTotalStake: stringToBn(result[5].toString()),
- minNominatorBond: stringToBn(result[6].toString()),
- totalStaked: stringToBn(result[7].toString()),
- counterForNominators: stringToBn(result[8].toString()),
+ totalValidators: stringToBn(result[0].toString()),
+ maxValidatorsCount: stringToBn(result[1].toString()),
+ validatorCount: stringToBn(result[2].toString()),
+ lastReward: stringToBn(result[3].toString()),
+ lastTotalStake: stringToBn(result[4].toString()),
+ minNominatorBond: stringToBn(result[5].toString()),
+ totalStaked: stringToBn(result[6].toString()),
+ counterForNominators: stringToBn(result[7].toString()),
};
document.dispatchEvent(
diff --git a/packages/app/src/pages/Overview/NetworkSats/index.tsx b/packages/app/src/pages/Overview/NetworkSats/index.tsx
index a6519210f..d21252ceb 100644
--- a/packages/app/src/pages/Overview/NetworkSats/index.tsx
+++ b/packages/app/src/pages/Overview/NetworkSats/index.tsx
@@ -15,7 +15,7 @@ export const NetworkStats = () => {
const { t } = useTranslation('pages');
const { bondedPools } = useBondedPools();
const { getAverageRewardRate } = useAverageRewardRate();
- const { totalNominators, totalValidators } = useApi().stakingMetrics;
+ const { counterForNominators, totalValidators } = useApi().stakingMetrics;
const { inflationToStakers } = getAverageRewardRate(false);
@@ -27,7 +27,7 @@ export const NetworkStats = () => {
},
{
label: t('overview.totalNominators'),
- value: totalNominators.toFormat(0),
+ value: counterForNominators.toFormat(0),
helpKey: 'Total Nominators',
},
{
From cd397306182fc14b1e7d66b74a4c975fa4dd93a2 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:15:03 +0700
Subject: [PATCH 07/84] activeEra to `Subscription`
---
packages/app/package.json | 1 +
.../src/model/Subscribe/ActiveEra/index.ts | 105 +++++++-----------
yarn.lock | 1 +
3 files changed, 44 insertions(+), 63 deletions(-)
diff --git a/packages/app/package.json b/packages/app/package.json
index c4b9eae02..34c8de028 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -73,6 +73,7 @@
"xxhash-wasm": "^1.0.2"
},
"devDependencies": {
+ "rxjs": "^7.8.1",
"vite": "^5.2.12",
"vite-bundle-visualizer": "^1.2.1",
"vite-plugin-checker": "^0.7.0",
diff --git a/packages/app/src/model/Subscribe/ActiveEra/index.ts b/packages/app/src/model/Subscribe/ActiveEra/index.ts
index 79f3f4848..e60a334d0 100644
--- a/packages/app/src/model/Subscribe/ActiveEra/index.ts
+++ b/packages/app/src/model/Subscribe/ActiveEra/index.ts
@@ -1,34 +1,26 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
import BigNumber from 'bignumber.js';
import { defaultActiveEra } from 'contexts/Api/defaults';
import type { APIActiveEra } from 'contexts/Api/types';
import { ApiController } from 'controllers/Api';
import { SubscriptionsController } from 'controllers/Subscriptions';
import type { Unsubscribable } from 'controllers/Subscriptions/types';
-import type { AnyApi, NetworkName } from 'types';
+import type { NetworkName } from 'types';
import { StakingMetrics } from '../StakingMetrics';
+import type { Subscription } from 'rxjs';
export class ActiveEra implements Unsubscribable {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// The associated network for this instance.
#network: NetworkName;
// Unsubscribe object.
- #unsub: VoidFn;
+ #unsub: Subscription;
// Store the active era.
activeEra: APIActiveEra = defaultActiveEra;
- // ------------------------------------------------------
- // Constructor.
- // ------------------------------------------------------
-
constructor(network: NetworkName) {
this.#network = network;
@@ -36,75 +28,62 @@ export class ActiveEra implements Unsubscribable {
this.subscribe();
}
- // ------------------------------------------------------
- // Subscription.
- // ------------------------------------------------------
-
subscribe = async (): Promise => {
try {
- const { api } = ApiController.get(this.#network);
+ const { api, papiApi } = ApiController.get(this.#network);
if (api && this.#unsub === undefined) {
- const unsub = await api.query.staking.activeEra((result: AnyApi) => {
- // determine activeEra: toString used as alternative to `toHuman`, that puts commas in
- // numbers
- const activeEra = JSON.parse(result.unwrapOrDefault().toString());
-
- // Return early if errornous active era is returned.
- if (activeEra.index === 0 || !activeEra.start) {
- return;
- }
-
- // Store active era.
- this.activeEra = {
- index: new BigNumber(activeEra.index),
- start: new BigNumber(activeEra.start),
- };
+ // Testing the active era subscription.
+ const unsub = papiApi.query.Staking.ActiveEra.watchValue().subscribe(
+ (activeEra) => {
+ // Store active era.
+ this.activeEra = {
+ index: new BigNumber(activeEra.index.toString()),
+ start: new BigNumber(activeEra.start.toString()),
+ };
+
+ // Unsubscribe to staking metrics if it exists.
+ const subStakingMetrics = SubscriptionsController.get(
+ this.#network,
+ 'stakingMetrics'
+ );
- // Unsubscribe to staking metrics if it exists.
- const subStakingMetrics = SubscriptionsController.get(
- this.#network,
- 'stakingMetrics'
- );
- if (subStakingMetrics) {
- subStakingMetrics.subscribe();
- SubscriptionsController.remove(this.#network, 'stakingMetrics');
- }
+ if (subStakingMetrics) {
+ subStakingMetrics.subscribe();
+ SubscriptionsController.remove(this.#network, 'stakingMetrics');
+ }
- // Subscribe to staking metrics with new active era.
- SubscriptionsController.set(
- this.#network,
- 'stakingMetrics',
- new StakingMetrics(
+ // Subscribe to staking metrics with new active era.
+ SubscriptionsController.set(
this.#network,
- this.activeEra,
- BigNumber.max(0, this.activeEra.index.minus(1))
- )
- );
-
- document.dispatchEvent(
- new CustomEvent('new-active-era', {
- detail: { activeEra },
- })
- );
- });
+ 'stakingMetrics',
+ new StakingMetrics(
+ this.#network,
+ this.activeEra,
+ BigNumber.max(0, this.activeEra.index.minus(1))
+ )
+ );
+
+ document.dispatchEvent(
+ new CustomEvent('new-active-era', {
+ detail: { activeEra },
+ })
+ );
+ }
+ );
// Subscription now initialised. Store unsub.
- this.#unsub = unsub as unknown as VoidFn;
+ this.#unsub = unsub;
}
} catch (e) {
// Block number subscription failed.
}
};
- // ------------------------------------------------------
- // Unsubscribe handler.
- // ------------------------------------------------------
-
// Unsubscribe from class subscription.
unsubscribe = (): void => {
- if (typeof this.#unsub === 'function') {
- this.#unsub();
+ if (typeof this.#unsub?.unsubscribe === 'function') {
+ this.#unsub.unsubscribe();
}
};
}
diff --git a/yarn.lock b/yarn.lock
index 7eee8079c..bd5810cd7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4908,6 +4908,7 @@ __metadata:
react-i18next: "npm:^15.0.2"
react-router-dom: "npm:^6.23.1"
react-scroll: "npm:^1.9.0"
+ rxjs: "npm:^7.8.1"
styled-components: "npm:^6.1.13"
styles: "workspace:*"
ui-buttons: "workspace:*"
From b6d019eba2e027e45a7e41883e98583de45c87f6 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:15:51 +0700
Subject: [PATCH 08/84] renames & fix
---
packages/app/src/contexts/Api/index.tsx | 2 +-
packages/app/src/model/Api/index.ts | 10 +++++-----
packages/app/src/model/Subscribe/ActiveEra/index.ts | 6 +++---
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 1931cab23..75dbd271f 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -164,7 +164,7 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// Bootstrap app-wide chain state.
const bootstrapNetworkConfig = async () => {
const apiInstance = ApiController.get(network);
- const pApi = apiInstance.papiApi;
+ const pApi = apiInstance.pApi;
// 1. Fetch network data for bootstrapping app state:
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index 4b3ac6a0d..8fcf8f825 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -39,7 +39,7 @@ export class Api {
#papiClient: PolkadotClient;
// PAPI API.
- #papiApi: PapiApi;
+ #pApi: PapiApi;
// PAPI Chain Spec.
#papiChainSpec: PapiChainSpec;
@@ -61,8 +61,8 @@ export class Api {
return this.#papiClient;
}
- get papiApi() {
- return this.#papiApi;
+ get pApi() {
+ return this.#pApi;
}
get papiChainSpec() {
@@ -113,7 +113,7 @@ export class Api {
await this.#api.isReady;
// Initialise PAPI API.
- this.#papiApi = this.#papiClient.getUnsafeApi();
+ this.#pApi = this.#papiClient.getUnsafeApi();
// Fetch chain spec and metadata from PAPI client.
await this.fetchChainSpec();
@@ -205,7 +205,7 @@ export class Api {
formatter?: 'asBytes'
): Promise => {
try {
- const result = await this.#papiApi.constants[pallet][key]();
+ const result = await this.#pApi.constants[pallet][key]();
switch (formatter) {
case 'asBytes':
diff --git a/packages/app/src/model/Subscribe/ActiveEra/index.ts b/packages/app/src/model/Subscribe/ActiveEra/index.ts
index e60a334d0..495344cdf 100644
--- a/packages/app/src/model/Subscribe/ActiveEra/index.ts
+++ b/packages/app/src/model/Subscribe/ActiveEra/index.ts
@@ -30,11 +30,11 @@ export class ActiveEra implements Unsubscribable {
subscribe = async (): Promise => {
try {
- const { api, papiApi } = ApiController.get(this.#network);
+ const { pApi } = ApiController.get(this.#network);
- if (api && this.#unsub === undefined) {
+ if (pApi && this.#unsub === undefined) {
// Testing the active era subscription.
- const unsub = papiApi.query.Staking.ActiveEra.watchValue().subscribe(
+ const unsub = pApi.query.Staking.ActiveEra.watchValue().subscribe(
(activeEra) => {
// Store active era.
this.activeEra = {
From 8f4984ecc72a4635717f812640470ce387fcc9be Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:20:04 +0700
Subject: [PATCH 09/84] `BlockNumber` to pApi, polish
---
.../src/model/Subscribe/ActiveEra/index.ts | 20 ++++-----
.../src/model/Subscribe/BlockNumber/index.ts | 41 +++++--------------
2 files changed, 18 insertions(+), 43 deletions(-)
diff --git a/packages/app/src/model/Subscribe/ActiveEra/index.ts b/packages/app/src/model/Subscribe/ActiveEra/index.ts
index 495344cdf..9df6b011a 100644
--- a/packages/app/src/model/Subscribe/ActiveEra/index.ts
+++ b/packages/app/src/model/Subscribe/ActiveEra/index.ts
@@ -15,16 +15,14 @@ export class ActiveEra implements Unsubscribable {
// The associated network for this instance.
#network: NetworkName;
- // Unsubscribe object.
- #unsub: Subscription;
+ // Active subscription.
+ #sub: Subscription;
// Store the active era.
activeEra: APIActiveEra = defaultActiveEra;
constructor(network: NetworkName) {
this.#network = network;
-
- // Subscribe immediately.
this.subscribe();
}
@@ -32,9 +30,9 @@ export class ActiveEra implements Unsubscribable {
try {
const { pApi } = ApiController.get(this.#network);
- if (pApi && this.#unsub === undefined) {
+ if (pApi && this.#sub === undefined) {
// Testing the active era subscription.
- const unsub = pApi.query.Staking.ActiveEra.watchValue().subscribe(
+ const sub = pApi.query.Staking.ActiveEra.watchValue().subscribe(
(activeEra) => {
// Store active era.
this.activeEra = {
@@ -71,19 +69,17 @@ export class ActiveEra implements Unsubscribable {
);
}
);
-
- // Subscription now initialised. Store unsub.
- this.#unsub = unsub;
+ this.#sub = sub;
}
} catch (e) {
- // Block number subscription failed.
+ // Subscription failed.
}
};
// Unsubscribe from class subscription.
unsubscribe = (): void => {
- if (typeof this.#unsub?.unsubscribe === 'function') {
- this.#unsub.unsubscribe();
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
}
};
}
diff --git a/packages/app/src/model/Subscribe/BlockNumber/index.ts b/packages/app/src/model/Subscribe/BlockNumber/index.ts
index 69a471116..43b93fbe0 100644
--- a/packages/app/src/model/Subscribe/BlockNumber/index.ts
+++ b/packages/app/src/model/Subscribe/BlockNumber/index.ts
@@ -1,47 +1,32 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
import { ApiController } from 'controllers/Api';
import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import type { Subscription } from 'rxjs';
import type { NetworkName } from 'types';
export class BlockNumber implements Unsubscribable {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// The associated network for this instance.
#network: NetworkName;
// The current block number.
blockNumber = '0';
- // Unsubscribe object.
- #unsub: VoidFn;
-
- // ------------------------------------------------------
- // Constructor.
- // ------------------------------------------------------
+ // Active subscription.
+ #sub: Subscription;
constructor(network: NetworkName) {
this.#network = network;
-
- // Subscribe immediately.
this.subscribe();
}
- // ------------------------------------------------------
- // Subscription.
- // ------------------------------------------------------
-
subscribe = async (): Promise => {
try {
- const { api } = ApiController.get(this.#network);
+ const { pApi } = ApiController.get(this.#network);
- if (api && this.#unsub === undefined) {
- // Get block numbers.
- const unsub = await api.query.system.number((num: number) => {
+ if (pApi && this.#sub === undefined) {
+ const unsub = pApi.query.System.Number.watchValue().subscribe((num) => {
// Update class block number.
this.blockNumber = num.toString();
@@ -54,23 +39,17 @@ export class BlockNumber implements Unsubscribable {
})
);
});
-
- // Subscription now initialised. Store unsub.
- this.#unsub = unsub as unknown as VoidFn;
+ this.#sub = unsub;
}
} catch (e) {
- // Block number subscription failed.
+ // Subscription failed.
}
};
- // ------------------------------------------------------
- // Unsubscribe handler.
- // ------------------------------------------------------
-
// Unsubscribe from class subscription.
unsubscribe = (): void => {
- if (typeof this.#unsub === 'function') {
- this.#unsub();
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
}
};
}
From 3bd6ee383baf2729e894f39efffe15f71285c85e Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:23:59 +0700
Subject: [PATCH 10/84] mx rxjs to deps
---
packages/app/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/app/package.json b/packages/app/package.json
index 34c8de028..7d7a14709 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -63,6 +63,7 @@
"react-i18next": "^15.0.2",
"react-router-dom": "^6.23.1",
"react-scroll": "^1.9.0",
+ "rxjs": "^7.8.1",
"styled-components": "^6.1.13",
"styles": "workspace:*",
"ui-buttons": "workspace:*",
@@ -73,7 +74,6 @@
"xxhash-wasm": "^1.0.2"
},
"devDependencies": {
- "rxjs": "^7.8.1",
"vite": "^5.2.12",
"vite-bundle-visualizer": "^1.2.1",
"vite-plugin-checker": "^0.7.0",
From 2448c996fc9d5d4ef7c24010b260e766ee538133 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:30:57 +0700
Subject: [PATCH 11/84] network metrics to rxjs
---
.../model/Subscribe/NetworkMetrics/index.ts | 74 ++++++++-----------
1 file changed, 29 insertions(+), 45 deletions(-)
diff --git a/packages/app/src/model/Subscribe/NetworkMetrics/index.ts b/packages/app/src/model/Subscribe/NetworkMetrics/index.ts
index e88874708..66728a7ff 100644
--- a/packages/app/src/model/Subscribe/NetworkMetrics/index.ts
+++ b/packages/app/src/model/Subscribe/NetworkMetrics/index.ts
@@ -1,61 +1,50 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
-import { rmCommas } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import { ApiController } from 'controllers/Api';
import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import type { Subscription } from 'rxjs';
+import { combineLatest } from 'rxjs';
import type { NetworkName } from 'types';
export class NetworkMetrics implements Unsubscribable {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// The associated network for this instance.
#network: NetworkName;
- // Unsubscribe object.
- #unsub: VoidFn;
-
- // ------------------------------------------------------
- // Constructor.
- // ------------------------------------------------------
+ // Active subscription.
+ #sub: Subscription;
constructor(network: NetworkName) {
this.#network = network;
-
- // Subscribe immediately.
this.subscribe();
}
- // ------------------------------------------------------
- // Subscription.
- // ------------------------------------------------------
-
subscribe = async (): Promise => {
try {
- const { api } = ApiController.get(this.#network);
+ const { pApi } = ApiController.get(this.#network);
- if (api && this.#unsub === undefined) {
- const unsub = await api.queryMulti(
- [
- api.query.balances.totalIssuance,
- api.query.auctions.auctionCounter,
- api.query.paraSessionInfo.earliestStoredSession,
- api.query.fastUnstake.erasToCheckPerBlock,
- api.query.staking.minimumActiveStake,
- ],
- (result) => {
+ if (pApi && this.#sub === undefined) {
+ const sub = combineLatest([
+ pApi.query.Balances.TotalIssuance.watchValue(),
+ pApi.query.Auctions.AuctionCounter.watchValue(),
+ pApi.query.ParaSessionInfo.EarliestStoredSession.watchValue(),
+ pApi.query.FastUnstake.ErasToCheckPerBlock.watchValue(),
+ pApi.query.Staking.MinimumActiveStake.watchValue(),
+ ]).subscribe(
+ ([
+ totalIssuance,
+ auctionCounter,
+ earliestStoredSession,
+ erasToCheckPerBlock,
+ minimumActiveStake,
+ ]) => {
const networkMetrics = {
- totalIssuance: new BigNumber(result[0].toString()),
- auctionCounter: new BigNumber(result[1].toString()),
- earliestStoredSession: new BigNumber(result[2].toString()),
- fastUnstakeErasToCheckPerBlock: Number(
- rmCommas(result[3].toString())
- ),
- minimumActiveStake: new BigNumber(result[4].toString()),
+ totalIssuance: new BigNumber(totalIssuance.toString()),
+ auctionCounter: new BigNumber(auctionCounter),
+ earliestStoredSession: new BigNumber(earliestStoredSession),
+ fastUnstakeErasToCheckPerBlock: Number(erasToCheckPerBlock),
+ minimumActiveStake: new BigNumber(minimumActiveStake.toString()),
};
document.dispatchEvent(
@@ -66,22 +55,17 @@ export class NetworkMetrics implements Unsubscribable {
}
);
- // Subscription now initialised. Store unsub.
- this.#unsub = unsub as unknown as VoidFn;
+ this.#sub = sub;
}
} catch (e) {
- // Block number subscription failed.
+ // Subscription failed.
}
};
- // ------------------------------------------------------
- // Unsubscribe handler.
- // ------------------------------------------------------
-
// Unsubscribe from class subscription.
unsubscribe = (): void => {
- if (typeof this.#unsub === 'function') {
- this.#unsub();
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
}
};
}
From 99bf80d9849c6be69c418d8013bae443efa77512 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:36:53 +0700
Subject: [PATCH 12/84] `PoolsConfig` to rxjs
---
.../src/model/Subscribe/PoolsConfig/index.ts | 116 +++++++++---------
1 file changed, 60 insertions(+), 56 deletions(-)
diff --git a/packages/app/src/model/Subscribe/PoolsConfig/index.ts b/packages/app/src/model/Subscribe/PoolsConfig/index.ts
index 1d6911741..4977602e7 100644
--- a/packages/app/src/model/Subscribe/PoolsConfig/index.ts
+++ b/packages/app/src/model/Subscribe/PoolsConfig/index.ts
@@ -1,28 +1,20 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
-import { rmCommas } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import { ApiController } from 'controllers/Api';
import type { Unsubscribable } from 'controllers/Subscriptions/types';
import type { NetworkName } from 'types';
import { stringToBn } from 'library/Utils';
+import type { Subscription } from 'rxjs';
+import { combineLatest } from 'rxjs';
export class PoolsConfig implements Unsubscribable {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// The associated network for this instance.
#network: NetworkName;
- // Unsubscribe object.
- #unsub: VoidFn;
-
- // ------------------------------------------------------
- // Constructor.
- // ------------------------------------------------------
+ // Active subscription.
+ #sub: Subscription;
constructor(network: NetworkName) {
this.#network = network;
@@ -31,54 +23,72 @@ export class PoolsConfig implements Unsubscribable {
this.subscribe();
}
- // ------------------------------------------------------
- // Subscription.
- // ------------------------------------------------------
-
subscribe = async (): Promise => {
try {
- const { api } = ApiController.get(this.#network);
-
- if (api && this.#unsub === undefined) {
- const unsub = await api.queryMulti(
- [
- api.query.nominationPools.counterForPoolMembers,
- api.query.nominationPools.counterForBondedPools,
- api.query.nominationPools.counterForRewardPools,
- api.query.nominationPools.lastPoolId,
- api.query.nominationPools.maxPoolMembers,
- api.query.nominationPools.maxPoolMembersPerPool,
- api.query.nominationPools.maxPools,
- api.query.nominationPools.minCreateBond,
- api.query.nominationPools.minJoinBond,
- api.query.nominationPools.globalMaxCommission,
- ],
- (result) => {
- // format optional configs to BigNumber or null.
- const maxPoolMembers = result[4].toHuman()
- ? new BigNumber(rmCommas(result[4].toString()))
+ const { pApi } = ApiController.get(this.#network);
+
+ if (pApi && this.#sub === undefined) {
+ const sub = combineLatest([
+ pApi.query.NominationPools.CounterForPoolMembers.watchValue(),
+ pApi.query.NominationPools.CounterForBondedPools.watchValue(),
+ pApi.query.NominationPools.CounterForRewardPools.watchValue(),
+ pApi.query.NominationPools.LastPoolId.watchValue(),
+ pApi.query.NominationPools.MaxPoolMembers.watchValue(),
+ pApi.query.NominationPools.MaxPoolMembersPerPool.watchValue(),
+ pApi.query.NominationPools.MaxPools.watchValue(),
+ pApi.query.NominationPools.MinCreateBond.watchValue(),
+ pApi.query.NominationPools.MinJoinBond.watchValue(),
+ pApi.query.NominationPools.GlobalMaxCommission.watchValue(),
+ ]).subscribe(
+ ([
+ counterForPoolMembers,
+ counterForBondedPools,
+ counterForRewardPools,
+ lastPoolId,
+ maxPoolMembersRaw,
+ maxPoolMembersPerPoolRaw,
+ maxPoolsRaw,
+ minCreateBond,
+ minJoinBond,
+ globalMaxCommission,
+ ]) => {
+ // Format globalMaxCommission from a perbill to a percent.
+ const globalMaxCommissionAsPercent =
+ BigInt(globalMaxCommission) / 1000000n;
+
+ // Format max pool members to be a BigNumber, or null if it's not set.
+ const maxPoolMembers = maxPoolMembersRaw
+ ? new BigNumber(maxPoolMembersRaw.toString())
: null;
- const maxPoolMembersPerPool = result[5].toHuman()
- ? new BigNumber(rmCommas(result[5].toString()))
+ // Format max pool members per pool to be a BigNumber, or null if it's not set.
+ const maxPoolMembersPerPool = maxPoolMembersPerPoolRaw
+ ? new BigNumber(maxPoolMembersPerPoolRaw.toString())
: null;
- const maxPools = result[6].toHuman()
- ? new BigNumber(rmCommas(result[6].toString()))
+ // Format max pools to be a BigNumber, or null if it's not set.
+ const maxPools = maxPoolsRaw
+ ? new BigNumber(maxPoolsRaw.toString())
: null;
const poolsConfig = {
- counterForPoolMembers: stringToBn(result[0].toString()),
- counterForBondedPools: stringToBn(result[1].toString()),
- counterForRewardPools: stringToBn(result[2].toString()),
- lastPoolId: stringToBn(result[3].toString()),
+ counterForPoolMembers: stringToBn(
+ counterForPoolMembers.toString()
+ ),
+ counterForBondedPools: stringToBn(
+ counterForBondedPools.toString()
+ ),
+ counterForRewardPools: stringToBn(
+ counterForRewardPools.toString()
+ ),
+ lastPoolId: stringToBn(lastPoolId.toString()),
maxPoolMembers,
maxPoolMembersPerPool,
maxPools,
- minCreateBond: stringToBn(result[7].toString()),
- minJoinBond: stringToBn(result[8].toString()),
+ minCreateBond: stringToBn(minCreateBond.toString()),
+ minJoinBond: stringToBn(minJoinBond.toString()),
globalMaxCommission: Number(
- String(result[9]?.toHuman() || '100%').slice(0, -1)
+ globalMaxCommissionAsPercent.toString()
),
};
@@ -89,23 +99,17 @@ export class PoolsConfig implements Unsubscribable {
);
}
);
-
- // Subscription now initialised. Store unsub.
- this.#unsub = unsub as unknown as VoidFn;
+ this.#sub = sub;
}
} catch (e) {
// Subscription failed.
}
};
- // ------------------------------------------------------
- // Unsubscribe handler.
- // ------------------------------------------------------
-
// Unsubscribe from class subscription.
unsubscribe = (): void => {
- if (typeof this.#unsub === 'function') {
- this.#unsub();
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
}
};
}
From 9f8ba8064fd1fc1fdac6c6f4cc617fe9b8b05ce8 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 11:42:26 +0700
Subject: [PATCH 13/84] `StakingMetrics` to rxjs
---
.../model/Subscribe/StakingMetrics/index.ts | 96 +++++++++----------
1 file changed, 44 insertions(+), 52 deletions(-)
diff --git a/packages/app/src/model/Subscribe/StakingMetrics/index.ts b/packages/app/src/model/Subscribe/StakingMetrics/index.ts
index e0032237c..221eac282 100644
--- a/packages/app/src/model/Subscribe/StakingMetrics/index.ts
+++ b/packages/app/src/model/Subscribe/StakingMetrics/index.ts
@@ -1,19 +1,16 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
import type BigNumber from 'bignumber.js';
import type { APIActiveEra } from 'contexts/Api/types';
import { ApiController } from 'controllers/Api';
import type { Unsubscribable } from 'controllers/Subscriptions/types';
import type { NetworkName } from 'types';
import { stringToBn } from 'library/Utils';
+import type { Subscription } from 'rxjs';
+import { combineLatest } from 'rxjs';
export class StakingMetrics implements Unsubscribable {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// The associated network for this instance.
#network: NetworkName;
@@ -21,12 +18,8 @@ export class StakingMetrics implements Unsubscribable {
#previousEra: BigNumber;
- // Unsubscribe object.
- #unsub: VoidFn;
-
- // ------------------------------------------------------
- // Constructor.
- // ------------------------------------------------------
+ // Active subscription.
+ #sub: Subscription;
constructor(
network: NetworkName,
@@ -41,42 +34,46 @@ export class StakingMetrics implements Unsubscribable {
this.subscribe();
}
- // ------------------------------------------------------
- // Subscription.
- // ------------------------------------------------------
-
subscribe = async (): Promise => {
try {
- const { api } = ApiController.get(this.#network);
+ const { pApi } = ApiController.get(this.#network);
- if (api && this.#unsub === undefined) {
- const unsub = await api.queryMulti(
- [
- api.query.staking.counterForValidators,
- api.query.staking.maxValidatorsCount,
- api.query.staking.validatorCount,
- [
- api.query.staking.erasValidatorReward,
- this.#previousEra.toString(),
- ],
- [api.query.staking.erasTotalStake, this.#previousEra.toString()],
- api.query.staking.minNominatorBond,
- [
- api.query.staking.erasTotalStake,
- this.#activeEra.index.toString(),
- ],
- api.query.staking.counterForNominators,
- ],
- (result) => {
+ if (pApi && this.#sub === undefined) {
+ const sub = combineLatest([
+ pApi.query.Staking.CounterForValidators.watchValue(),
+ pApi.query.Staking.MaxValidatorsCount.watchValue(),
+ pApi.query.Staking.ValidatorCount.watchValue(),
+ pApi.query.Staking.ErasValidatorReward.watchValue(
+ this.#previousEra.toString()
+ ),
+ pApi.query.Staking.ErasTotalStake.watchValue(
+ this.#previousEra.toString()
+ ),
+ pApi.query.Staking.MinNominatorBond.watchValue(),
+ pApi.query.Staking.ErasTotalStake.watchValue(
+ this.#activeEra.index.toString()
+ ),
+ pApi.query.Staking.CounterForNominators.watchValue(),
+ ]).subscribe(
+ ([
+ counterForValidators,
+ maxValidatorsCount,
+ validatorCount,
+ erasValidatorReward,
+ lastTotalStake,
+ minNominatorBond,
+ totalStaked,
+ counterForNominators,
+ ]) => {
const stakingMetrics = {
- totalValidators: stringToBn(result[0].toString()),
- maxValidatorsCount: stringToBn(result[1].toString()),
- validatorCount: stringToBn(result[2].toString()),
- lastReward: stringToBn(result[3].toString()),
- lastTotalStake: stringToBn(result[4].toString()),
- minNominatorBond: stringToBn(result[5].toString()),
- totalStaked: stringToBn(result[6].toString()),
- counterForNominators: stringToBn(result[7].toString()),
+ totalValidators: stringToBn(counterForValidators.toString()),
+ maxValidatorsCount: stringToBn(maxValidatorsCount.toString()),
+ validatorCount: stringToBn(validatorCount.toString()),
+ lastReward: stringToBn(erasValidatorReward.toString()),
+ lastTotalStake: stringToBn(lastTotalStake.toString()),
+ minNominatorBond: stringToBn(minNominatorBond.toString()),
+ totalStaked: stringToBn(totalStaked.toString()),
+ counterForNominators: stringToBn(counterForNominators.toString()),
};
document.dispatchEvent(
@@ -86,22 +83,17 @@ export class StakingMetrics implements Unsubscribable {
);
}
);
- // Subscription now initialised. Store unsub.
- this.#unsub = unsub as unknown as VoidFn;
+ this.#sub = sub;
}
} catch (e) {
- // Block number subscription failed.
+ // Subscription failed.
}
};
- // ------------------------------------------------------
- // Unsubscribe handler.
- // ------------------------------------------------------
-
// Unsubscribe from class subscription.
unsubscribe = (): void => {
- if (typeof this.#unsub === 'function') {
- this.#unsub();
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
}
};
}
From 197ecf0949293c386c1a4e8c4e6365fe5a18d339 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 13:39:28 +0700
Subject: [PATCH 14/84] version info to chainSpecs
---
packages/app/src/contexts/Api/defaults.ts | 17 +++----
packages/app/src/contexts/Api/index.tsx | 48 ++++++++-----------
packages/app/src/contexts/Api/types.ts | 8 ----
.../app/src/contexts/LedgerHardware/index.tsx | 4 +-
packages/app/src/model/Api/index.ts | 17 +++++++
packages/app/src/model/Api/types.ts | 8 ++++
6 files changed, 55 insertions(+), 47 deletions(-)
diff --git a/packages/app/src/contexts/Api/defaults.ts b/packages/app/src/contexts/Api/defaults.ts
index 40ebace65..6c03b014a 100644
--- a/packages/app/src/contexts/Api/defaults.ts
+++ b/packages/app/src/contexts/Api/defaults.ts
@@ -6,7 +6,6 @@ import { stringToU8a } from '@polkadot/util';
import BigNumber from 'bignumber.js';
import type {
APIActiveEra,
- APIChainState,
APIConstants,
APIContextInterface,
APINetworkMetrics,
@@ -15,14 +14,6 @@ import type {
PapiChainSpecContext,
} from 'contexts/Api/types';
-export const defaultChainState: APIChainState = {
- chain: null,
- version: {
- specVersion: 0,
- },
- ss58Prefix: 0,
-};
-
export const defaultConsts: APIConstants = {
bondDuration: new BigNumber(0),
maxNominations: new BigNumber(0),
@@ -50,6 +41,13 @@ export const defaultChainSpecs: PapiChainSpecContext = {
tokenDecimals: 0,
tokenSymbol: '',
received: false,
+ authoringVersion: 0,
+ implName: '',
+ implVersion: 0,
+ specName: '',
+ specVersion: 0,
+ stateVersion: 0,
+ transactionVersion: 0,
};
export const defaultActiveEra: APIActiveEra = {
@@ -84,7 +82,6 @@ export const defaultStakingMetrics: APIStakingMetrics = {
export const defaultApiContext: APIContextInterface = {
api: null,
peopleApi: null,
- chainState: defaultChainState,
chainSpecs: defaultChainSpecs,
isReady: false,
apiStatus: 'disconnected',
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 75dbd271f..30622554c 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -7,7 +7,6 @@ import { NetworkList } from 'config/networks';
import type {
APIActiveEra,
- APIChainState,
APIConstants,
APIContextInterface,
APINetworkMetrics,
@@ -21,7 +20,6 @@ import {
defaultConsts,
defaultActiveEra,
defaultApiContext,
- defaultChainState,
defaultPoolsConfig,
defaultNetworkMetrics,
defaultStakingMetrics,
@@ -106,10 +104,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
setRpcEndpointState(key);
};
- // Store chain state.
- const [chainState, setChainState] =
- useState(defaultChainState);
-
// Store network constants.
const [consts, setConsts] = useState(defaultConsts);
@@ -140,23 +134,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// Fetch chain state. Called once `provider` has been initialised.
const onApiReady = async () => {
- const { api } = ApiController.get(network);
-
- const newChainState = await Promise.all([
- api.rpc.system.chain(),
- api.consts.system.version,
- api.consts.system.ss58Prefix,
- ]);
-
- // Check that chain values have been fetched before committing to state. Could be expanded to
- // check supported chains.
- if (newChainState.every((c) => !!c?.toHuman())) {
- const chain = newChainState[0]?.toString();
- const version = newChainState[1]?.toJSON();
- const ss58Prefix = Number(newChainState[2]?.toString());
- setChainState({ chain, version, ss58Prefix });
- }
-
// Assume chain state is correct and bootstrap network consts.
bootstrapNetworkConfig();
};
@@ -225,8 +202,20 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
const handlePapiReady = async (e: Event) => {
if (isCustomEvent(e)) {
- const { chainType, genesisHash, ss58Format, tokenDecimals, tokenSymbol } =
- e.detail;
+ const {
+ chainType,
+ genesisHash,
+ ss58Format,
+ tokenDecimals,
+ tokenSymbol,
+ authoringVersion,
+ implName,
+ implVersion,
+ specName,
+ specVersion,
+ stateVersion,
+ transactionVersion,
+ } = e.detail;
if (chainType === 'relay') {
const newChainSpecs: PapiChainSpecContext = {
@@ -234,6 +223,13 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
ss58Format,
tokenDecimals,
tokenSymbol,
+ authoringVersion,
+ implName,
+ implVersion,
+ specName,
+ specVersion,
+ stateVersion,
+ transactionVersion,
received: true,
};
@@ -515,7 +511,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// Reset consts and chain state.
setChainSpecs(defaultChainSpecs);
setConsts(defaultConsts);
- setChainState(defaultChainState);
setStateWithRef(
defaultNetworkMetrics,
setNetworkMetrics,
@@ -563,7 +558,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
value={{
api: ApiController.get(network)?.api || null,
peopleApi: ApiController.get(`people-${network}`)?.api || null,
- chainState,
chainSpecs,
apiStatus,
peopleApiStatus,
diff --git a/packages/app/src/contexts/Api/types.ts b/packages/app/src/contexts/Api/types.ts
index 5dd28bc86..0ce64eeb7 100644
--- a/packages/app/src/contexts/Api/types.ts
+++ b/packages/app/src/contexts/Api/types.ts
@@ -6,19 +6,12 @@ import type BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import type { NetworkName } from '../../types';
import type { ApiStatus, ConnectionType, PapiChainSpec } from 'model/Api/types';
-import type { AnyJson } from '@w3ux/types';
export interface APIProviderProps {
children: ReactNode;
network: NetworkName;
}
-export interface APIChainState {
- chain: string | null;
- version: AnyJson;
- ss58Prefix: number;
-}
-
export interface APIConstants {
bondDuration: BigNumber;
maxNominations: BigNumber;
@@ -75,7 +68,6 @@ export interface APIStakingMetrics {
export interface APIContextInterface {
api: ApiPromise | null;
peopleApi: ApiPromise | null;
- chainState: APIChainState;
chainSpecs: PapiChainSpecContext;
isReady: boolean;
apiStatus: ApiStatus;
diff --git a/packages/app/src/contexts/LedgerHardware/index.tsx b/packages/app/src/contexts/LedgerHardware/index.tsx
index ef12b8da8..0b80c4a67 100644
--- a/packages/app/src/contexts/LedgerHardware/index.tsx
+++ b/packages/app/src/contexts/LedgerHardware/index.tsx
@@ -31,8 +31,8 @@ export const LedgerHardwareProvider = ({
children: ReactNode;
}) => {
const { t } = useTranslation('modals');
- const { chainState } = useApi();
- const { transactionVersion } = chainState.version;
+ const { chainSpecs } = useApi();
+ const { transactionVersion } = chainSpecs;
// Store whether a Ledger device task is in progress.
const [isExecuting, setIsExecutingState] = useState(false);
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index 8fcf8f825..f8c15e9d4 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -175,15 +175,32 @@ export class Api {
async fetchChainSpec() {
try {
const chainSpecData = await this.#papiClient.getChainSpecData();
+ const version = await this.#pApi.constants.System.Version();
const { genesisHash, properties } = chainSpecData;
const { ss58Format, tokenDecimals, tokenSymbol } = properties;
+ const {
+ authoring_version: authoringVersion,
+ impl_name: implName,
+ impl_version: implVersion,
+ spec_name: specName,
+ spec_version: specVersion,
+ state_version: stateVersion,
+ transaction_version: transactionVersion,
+ } = version;
this.#papiChainSpec = {
genesisHash,
ss58Format,
tokenDecimals,
tokenSymbol,
+ authoringVersion,
+ implName,
+ implVersion,
+ specName,
+ specVersion,
+ stateVersion,
+ transactionVersion,
};
// Dispatch 'papi-ready' event to let contexts populate constants.
diff --git a/packages/app/src/model/Api/types.ts b/packages/app/src/model/Api/types.ts
index eaae0bf6f..efbea3b02 100644
--- a/packages/app/src/model/Api/types.ts
+++ b/packages/app/src/model/Api/types.ts
@@ -23,7 +23,15 @@ export interface PapiChainSpec {
ss58Format: number;
tokenDecimals: number;
tokenSymbol: string;
+ authoringVersion: number;
+ implName: string;
+ implVersion: number;
+ specName: string;
+ specVersion: number;
+ stateVersion: number;
+ transactionVersion: number;
}
+
export type PapiReadyEvent = PapiChainSpec & {
network: NetworkName | SystemChainId;
chainType: string;
From a4eeb55487b90dad3de61326f7927c7580d8f85b Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 13:45:20 +0700
Subject: [PATCH 15/84] rename
---
packages/app/src/model/Query/Era/index.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/app/src/model/Query/Era/index.ts b/packages/app/src/model/Query/Era/index.ts
index fb83230c7..dd1bf8f9a 100644
--- a/packages/app/src/model/Query/Era/index.ts
+++ b/packages/app/src/model/Query/Era/index.ts
@@ -6,10 +6,10 @@ import type { PapiApi } from 'model/Api/types';
export class Era {
// Fetch network constants.
- async fetch(api: PapiApi) {
+ async fetch(pApi: PapiApi) {
let result;
try {
- const { index, start } = await api.query.Staking.ActiveEra.getValue();
+ const { index, start } = await pApi.query.Staking.ActiveEra.getValue();
result = {
start,
index,
From 286d2f562f9df03190c0b9d81ec164b3fed450ce Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 16:24:19 +0700
Subject: [PATCH 16/84] `ValidatorEntries` to query class
---
.../Validators/ValidatorEntries/index.tsx | 45 +++++++++++--------
packages/app/src/library/Utils/index.ts | 4 ++
.../src/model/Query/ValidatorEntries/index.ts | 16 +++++++
3 files changed, 46 insertions(+), 19 deletions(-)
create mode 100644 packages/app/src/model/Query/ValidatorEntries/index.ts
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index 452b4be00..3b510d52e 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -33,6 +33,9 @@ import { getLocalEraValidators, setLocalEraValidators } from '../Utils';
import { useErasPerDay } from 'hooks/useErasPerDay';
import { IdentitiesController } from 'controllers/Identities';
import type { AnyJson, Sync } from '@w3ux/types';
+import { ValidatorEntries } from 'model/Query/ValidatorEntries';
+import { ApiController } from 'controllers/Api';
+import { perbillToPercent } from 'library/Utils';
export const ValidatorsContext = createContext(
defaultValidatorsContext
@@ -240,34 +243,38 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// Fetch validator entries and format the returning data.
const getValidatorEntries = async () => {
- if (!isReady || !api) {
+ if (!isReady) {
return defaultValidatorsData;
}
- const result = await api.query.staking.validators.entries();
+ const { pApi } = ApiController.get(network);
+ const result = await new ValidatorEntries(pApi).fetch();
const entries: Validator[] = [];
let notFullCommissionCount = 0;
let totalNonAllCommission = new BigNumber(0);
- result.forEach(([a, p]: AnyApi) => {
- const address = a.toHuman().pop();
- const prefs = p.toHuman();
- const commission = new BigNumber(prefs.commission.replace(/%/g, ''));
+ result.forEach(
+ ({ keyArgs: [address], value: { commission, blocked } }: AnyApi) => {
+ const commissionAsPercent = new BigNumber(
+ perbillToPercent(new BigNumber(commission)).toString()
+ );
+
+ if (!commissionAsPercent.isEqualTo(100)) {
+ totalNonAllCommission =
+ totalNonAllCommission.plus(commissionAsPercent);
+ } else {
+ notFullCommissionCount++;
+ }
- if (!commission.isEqualTo(100)) {
- totalNonAllCommission = totalNonAllCommission.plus(commission);
- } else {
- notFullCommissionCount++;
+ entries.push({
+ address,
+ prefs: {
+ commission: Number(commissionAsPercent.toFixed(2)),
+ blocked,
+ },
+ });
}
-
- entries.push({
- address,
- prefs: {
- commission: Number(commission.toFixed(2)),
- blocked: prefs.blocked,
- },
- });
- });
+ );
return { entries, notFullCommissionCount, totalNonAllCommission };
};
diff --git a/packages/app/src/library/Utils/index.ts b/packages/app/src/library/Utils/index.ts
index e0854c009..8aa038460 100644
--- a/packages/app/src/library/Utils/index.ts
+++ b/packages/app/src/library/Utils/index.ts
@@ -78,3 +78,7 @@ export const timeleftAsString = (
}
return str;
};
+
+// Convert a perbill BigNumber value into a percentage.
+export const perbillToPercent = (value: BigNumber): BigNumber =>
+ value.dividedBy('10000000');
diff --git a/packages/app/src/model/Query/ValidatorEntries/index.ts b/packages/app/src/model/Query/ValidatorEntries/index.ts
new file mode 100644
index 000000000..2c248b348
--- /dev/null
+++ b/packages/app/src/model/Query/ValidatorEntries/index.ts
@@ -0,0 +1,16 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ValidatorEntries {
+ #pApi: PapiApi;
+
+ constructor(pApi: PapiApi) {
+ this.#pApi = pApi;
+ }
+
+ async fetch() {
+ return await this.#pApi.query.Staking.Validators.getEntries();
+ }
+}
From 6dedac21e6b5cc45e07437f786e5d49417d5af40 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 16:27:30 +0700
Subject: [PATCH 17/84] fix, api to constructor
---
packages/app/src/contexts/Api/index.tsx | 17 ++---
packages/app/src/model/Query/Era/index.ts | 12 +++-
.../app/src/model/Query/NetworkMeta/index.ts | 65 +++++++++++--------
3 files changed, 54 insertions(+), 40 deletions(-)
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 30622554c..279eac3cd 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -132,12 +132,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
const [chainSpecs, setChainSpecs] =
useState(defaultChainSpecs);
- // Fetch chain state. Called once `provider` has been initialised.
- const onApiReady = async () => {
- // Assume chain state is correct and bootstrap network consts.
- bootstrapNetworkConfig();
- };
-
// Bootstrap app-wide chain state.
const bootstrapNetworkConfig = async () => {
const apiInstance = ApiController.get(network);
@@ -146,16 +140,16 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
// 1. Fetch network data for bootstrapping app state:
// Get active and previous era.
- const { activeEra: newActiveEra, previousEra } = await new Era().fetch(
+ const { activeEra: newActiveEra, previousEra } = await new Era(
pApi
- );
+ ).fetch();
// Get network meta data related to staking and pools.
const {
networkMetrics: newNetworkMetrics,
poolsConfig: newPoolsConfig,
stakingMetrics: newStakingMetrics,
- } = await new NetworkMeta().fetch(pApi, newActiveEra, previousEra);
+ } = await new NetworkMeta(pApi).fetch(newActiveEra, previousEra);
// 2. Populate all config state:
@@ -291,6 +285,8 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
fastUnstakeDeposit: new BigNumber(fastUnstakeDeposit.toString()),
poolsPalletId,
});
+
+ bootstrapNetworkConfig();
}
}
};
@@ -326,9 +322,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
return;
}
switch (status) {
- case 'ready':
- onApiReady();
- break;
case 'connecting':
setApiStatus('connecting');
break;
diff --git a/packages/app/src/model/Query/Era/index.ts b/packages/app/src/model/Query/Era/index.ts
index dd1bf8f9a..284b78929 100644
--- a/packages/app/src/model/Query/Era/index.ts
+++ b/packages/app/src/model/Query/Era/index.ts
@@ -5,11 +5,19 @@ import BigNumber from 'bignumber.js';
import type { PapiApi } from 'model/Api/types';
export class Era {
+ #pApi: PapiApi;
+
+ constructor(pApi: PapiApi) {
+ this.#pApi = pApi;
+ }
+
// Fetch network constants.
- async fetch(pApi: PapiApi) {
+ async fetch() {
let result;
try {
- const { index, start } = await pApi.query.Staking.ActiveEra.getValue();
+ const { index, start } =
+ await this.#pApi.query.Staking.ActiveEra.getValue();
+
result = {
start,
index,
diff --git a/packages/app/src/model/Query/NetworkMeta/index.ts b/packages/app/src/model/Query/NetworkMeta/index.ts
index b4e14211b..917d3334d 100644
--- a/packages/app/src/model/Query/NetworkMeta/index.ts
+++ b/packages/app/src/model/Query/NetworkMeta/index.ts
@@ -3,13 +3,20 @@
import BigNumber from 'bignumber.js';
import type { APIActiveEra } from 'contexts/Api/types';
-import { stringToBn } from 'library/Utils';
+import { perbillToPercent, stringToBn } from 'library/Utils';
import type { PapiApi } from 'model/Api/types';
export class NetworkMeta {
+ #pApi: PapiApi;
+
+ constructor(pApi: PapiApi) {
+ this.#pApi = pApi;
+ }
+
// Fetch network constants.
- async fetch(pApi: PapiApi, activeEra: APIActiveEra, previousEra: BigNumber) {
- const totalIssuance = await pApi.query.Balances.TotalIssuance.getValue();
+ async fetch(activeEra: APIActiveEra, previousEra: BigNumber) {
+ const totalIssuance =
+ await this.#pApi.query.Balances.TotalIssuance.getValue();
const [
auctionCounter,
@@ -35,32 +42,38 @@ export class NetworkMeta {
minNominatorBond,
activeEraErasTotalStake,
] = await Promise.all([
- pApi.query.Auctions.AuctionCounter.getValue(),
- pApi.query.ParaSessionInfo.EarliestStoredSession.getValue(),
- pApi.query.FastUnstake.ErasToCheckPerBlock.getValue(),
- pApi.query.Staking.MinimumActiveStake.getValue(),
- pApi.query.NominationPools.CounterForPoolMembers.getValue(),
- pApi.query.NominationPools.CounterForBondedPools.getValue(),
- pApi.query.NominationPools.CounterForRewardPools.getValue(),
- pApi.query.NominationPools.LastPoolId.getValue(),
- pApi.query.NominationPools.MaxPoolMembers.getValue(),
- pApi.query.NominationPools.MaxPoolMembersPerPool.getValue(),
- pApi.query.NominationPools.MaxPools.getValue(),
- pApi.query.NominationPools.MinCreateBond.getValue(),
- pApi.query.NominationPools.MinJoinBond.getValue(),
- pApi.query.NominationPools.GlobalMaxCommission.getValue(),
- pApi.query.Staking.CounterForNominators.getValue(),
- pApi.query.Staking.CounterForValidators.getValue(),
- pApi.query.Staking.MaxValidatorsCount.getValue(),
- pApi.query.Staking.ValidatorCount.getValue(),
- pApi.query.Staking.ErasValidatorReward.getValue(previousEra.toString()),
- pApi.query.Staking.ErasTotalStake.getValue(previousEra.toString()),
- pApi.query.Staking.MinNominatorBond.getValue(),
- pApi.query.Staking.ErasTotalStake.getValue(activeEra.index.toString()),
+ this.#pApi.query.Auctions.AuctionCounter.getValue(),
+ this.#pApi.query.ParaSessionInfo.EarliestStoredSession.getValue(),
+ this.#pApi.query.FastUnstake.ErasToCheckPerBlock.getValue(),
+ this.#pApi.query.Staking.MinimumActiveStake.getValue(),
+ this.#pApi.query.NominationPools.CounterForPoolMembers.getValue(),
+ this.#pApi.query.NominationPools.CounterForBondedPools.getValue(),
+ this.#pApi.query.NominationPools.CounterForRewardPools.getValue(),
+ this.#pApi.query.NominationPools.LastPoolId.getValue(),
+ this.#pApi.query.NominationPools.MaxPoolMembers.getValue(),
+ this.#pApi.query.NominationPools.MaxPoolMembersPerPool.getValue(),
+ this.#pApi.query.NominationPools.MaxPools.getValue(),
+ this.#pApi.query.NominationPools.MinCreateBond.getValue(),
+ this.#pApi.query.NominationPools.MinJoinBond.getValue(),
+ this.#pApi.query.NominationPools.GlobalMaxCommission.getValue(),
+ this.#pApi.query.Staking.CounterForNominators.getValue(),
+ this.#pApi.query.Staking.CounterForValidators.getValue(),
+ this.#pApi.query.Staking.MaxValidatorsCount.getValue(),
+ this.#pApi.query.Staking.ValidatorCount.getValue(),
+ this.#pApi.query.Staking.ErasValidatorReward.getValue(
+ previousEra.toString()
+ ),
+ this.#pApi.query.Staking.ErasTotalStake.getValue(previousEra.toString()),
+ this.#pApi.query.Staking.MinNominatorBond.getValue(),
+ this.#pApi.query.Staking.ErasTotalStake.getValue(
+ activeEra.index.toString()
+ ),
]);
// Format globalMaxCommission from a perbill to a percent.
- const globalMaxCommissionAsPercent = BigInt(globalMaxCommission) / 1000000n;
+ const globalMaxCommissionAsPercent = perbillToPercent(
+ new BigNumber(globalMaxCommission)
+ );
// Format max pool members to be a BigNumber, or null if it's not set.
const maxPoolMembers = maxPoolMembersRaw
From 3617108edf6a8c6606601b58168b9530fa8703d3 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 16:35:33 +0700
Subject: [PATCH 18/84] `ErasStakersOverview` to Query class
---
packages/app/src/contexts/Staking/index.tsx | 24 ++++++++++---------
.../model/Query/ErasStakersOverview/index.tsx | 16 +++++++++++++
2 files changed, 29 insertions(+), 11 deletions(-)
create mode 100644 packages/app/src/model/Query/ErasStakersOverview/index.tsx
diff --git a/packages/app/src/contexts/Staking/index.tsx b/packages/app/src/contexts/Staking/index.tsx
index bc8ea15db..50a9bf25d 100644
--- a/packages/app/src/contexts/Staking/index.tsx
+++ b/packages/app/src/contexts/Staking/index.tsx
@@ -25,6 +25,9 @@ import { defaultEraStakers, defaultStakingContext } from './defaults';
import { setLocalEraExposures, getLocalEraExposures } from './Utils';
import type { NominationStatus } from 'library/ValidatorList/ValidatorItem/types';
import { SyncController } from 'controllers/Sync';
+import { ErasStakersOverview } from 'model/Query/ErasStakersOverview';
+import { ApiController } from 'controllers/Api';
+import type { AnyJson } from '@w3ux/types';
const worker = new Worker();
@@ -38,9 +41,9 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
const { getBondedAccount } = useBonded();
const { networkData, network } = useNetwork();
const { getLedger, getNominations } = useBalances();
+ const { isReady, api, activeEra, apiStatus } = useApi();
const { accounts: connectAccounts } = useImportedAccounts();
const { activeAccount, getActiveAccount } = useActiveAccounts();
- const { isReady, api, apiStatus, activeEra } = useApi();
// Store eras stakers in state.
const [eraStakers, setEraStakers] = useState(defaultEraStakers);
@@ -225,15 +228,14 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
return [];
}
- const overview: AnyApi =
- await api.query.staking.erasStakersOverview.entries(era);
+ const { pApi } = ApiController.get(network);
+ const overviewNew = await new ErasStakersOverview(pApi).fetch(era);
- const validators = overview.reduce(
- (prev: Record, [keys, value]: AnyApi) => {
- const validator = keys.toHuman()[1];
- const { own, total } = value.toHuman();
- return { ...prev, [validator]: { own, total } };
- },
+ const validators: Record = overviewNew.reduce(
+ (
+ prev: Record,
+ { keyArgs: [, validator], value: { own, total } }: AnyApi
+ ) => ({ ...prev, [validator]: { own, total } }),
{}
);
const validatorKeys = Object.keys(validators);
@@ -263,8 +265,8 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
result.push({
keys: [rmCommas(era), validator],
val: {
- total: rmCommas(total),
- own: rmCommas(own),
+ total: total.toString(),
+ own: own.toString(),
others: others.map(({ who, value }) => ({
who,
value: rmCommas(value),
diff --git a/packages/app/src/model/Query/ErasStakersOverview/index.tsx b/packages/app/src/model/Query/ErasStakersOverview/index.tsx
new file mode 100644
index 000000000..8c42b5d3a
--- /dev/null
+++ b/packages/app/src/model/Query/ErasStakersOverview/index.tsx
@@ -0,0 +1,16 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ErasStakersOverview {
+ #pApi: PapiApi;
+
+ constructor(pApi: PapiApi) {
+ this.#pApi = pApi;
+ }
+
+ async fetch(era: string) {
+ return await this.#pApi.query.Staking.ErasStakersOverview.getEntries(era);
+ }
+}
From 659776b8df92657306447104dcc259d2e8d6b8ca Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 15 Nov 2024 16:44:52 +0700
Subject: [PATCH 19/84] `ErasStakersPaged` to Query class
---
packages/app/src/contexts/Staking/index.tsx | 42 ++++++++-----------
.../app/src/model/ErasStakersPaged/index.tsx | 19 +++++++++
2 files changed, 37 insertions(+), 24 deletions(-)
create mode 100644 packages/app/src/model/ErasStakersPaged/index.tsx
diff --git a/packages/app/src/contexts/Staking/index.tsx b/packages/app/src/contexts/Staking/index.tsx
index 50a9bf25d..2ca9f5b1e 100644
--- a/packages/app/src/contexts/Staking/index.tsx
+++ b/packages/app/src/contexts/Staking/index.tsx
@@ -1,7 +1,7 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { rmCommas, setStateWithRef } from '@w3ux/utils';
+import { setStateWithRef } from '@w3ux/utils';
import type { ReactNode } from 'react';
import { createContext, useContext, useRef, useState } from 'react';
import { useBalances } from 'contexts/Balances';
@@ -9,7 +9,6 @@ import type { ExternalAccount } from '@w3ux/react-connect-kit/types';
import type {
EraStakers,
Exposure,
- ExposureOther,
StakingContextInterface,
} from 'contexts/Staking/types';
import type { AnyApi, MaybeAddress } from 'types';
@@ -28,6 +27,7 @@ import { SyncController } from 'controllers/Sync';
import { ErasStakersOverview } from 'model/Query/ErasStakersOverview';
import { ApiController } from 'controllers/Api';
import type { AnyJson } from '@w3ux/types';
+import { ErasStakersPaged } from 'model/ErasStakersPaged';
const worker = new Worker();
@@ -229,9 +229,8 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
}
const { pApi } = ApiController.get(network);
- const overviewNew = await new ErasStakersOverview(pApi).fetch(era);
-
- const validators: Record = overviewNew.reduce(
+ const overview = await new ErasStakersOverview(pApi).fetch(era);
+ const validators: Record = overview.reduce(
(
prev: Record,
{ keyArgs: [, validator], value: { own, total } }: AnyApi
@@ -241,36 +240,31 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
const validatorKeys = Object.keys(validators);
const pagedResults = await Promise.all(
- validatorKeys.map((v) =>
- api.query.staking.erasStakersPaged.entries(era, v)
- )
+ validatorKeys.map((v) => new ErasStakersPaged(pApi).fetch(era, v))
);
const result: Exposure[] = [];
let i = 0;
- for (const pagedResult of pagedResults) {
+ for (const [
+ {
+ keyArgs,
+ value: { others },
+ },
+ ] of pagedResults) {
const validator = validatorKeys[i];
const { own, total } = validators[validator];
- const others = pagedResult.reduce(
- (prev: ExposureOther[], [, v]: AnyApi) => {
- const o = v.toHuman()?.others || [];
- if (!o.length) {
- return prev;
- }
- return prev.concat(o);
- },
- []
- );
result.push({
- keys: [rmCommas(era), validator],
+ keys: [keyArgs[0].toString(), validator],
val: {
total: total.toString(),
own: own.toString(),
- others: others.map(({ who, value }) => ({
- who,
- value: rmCommas(value),
- })),
+ others: others.map(
+ ({ who, value }: { who: string; value: bigint }) => ({
+ who,
+ value: value.toString(),
+ })
+ ),
},
});
i++;
diff --git a/packages/app/src/model/ErasStakersPaged/index.tsx b/packages/app/src/model/ErasStakersPaged/index.tsx
new file mode 100644
index 000000000..a7a3a57f3
--- /dev/null
+++ b/packages/app/src/model/ErasStakersPaged/index.tsx
@@ -0,0 +1,19 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ErasStakersPaged {
+ #pApi: PapiApi;
+
+ constructor(pApi: PapiApi) {
+ this.#pApi = pApi;
+ }
+
+ async fetch(era: string, validator: string) {
+ return await this.#pApi.query.Staking.ErasStakersPaged.getEntries(
+ era,
+ validator
+ );
+ }
+}
From da70698a435632463cef744715cf32404edc1c89 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Sat, 16 Nov 2024 09:39:25 +0700
Subject: [PATCH 20/84] add `BondedPoolsEntries` Query class
---
.../src/contexts/Pools/BondedPools/index.tsx | 25 ++++---
.../Validators/ValidatorEntries/index.tsx | 4 +-
packages/app/src/library/Utils/index.ts | 10 ++-
.../model/Query/BondedPoolsEntries/index.tsx | 66 +++++++++++++++++++
.../app/src/model/Query/NetworkMeta/index.ts | 6 +-
5 files changed, 94 insertions(+), 17 deletions(-)
create mode 100644 packages/app/src/model/Query/BondedPoolsEntries/index.tsx
diff --git a/packages/app/src/contexts/Pools/BondedPools/index.tsx b/packages/app/src/contexts/Pools/BondedPools/index.tsx
index 02a502981..e089231cf 100644
--- a/packages/app/src/contexts/Pools/BondedPools/index.tsx
+++ b/packages/app/src/contexts/Pools/BondedPools/index.tsx
@@ -23,6 +23,8 @@ import { useApi } from '../../Api';
import { defaultBondedPoolsContext } from './defaults';
import { useCreatePoolAccounts } from 'hooks/useCreatePoolAccounts';
import { SyncController } from 'controllers/Sync';
+import { BondedPoolsEntries } from 'model/Query/BondedPoolsEntries';
+import { ApiController } from 'controllers/Api';
export const BondedPoolsContext = createContext(
defaultBondedPoolsContext
@@ -63,21 +65,26 @@ export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
// Fetch all bonded pool entries and their metadata.
const fetchBondedPools = async () => {
- if (!api || bondedPoolsSynced.current !== 'unsynced') {
+ const { pApi } = ApiController.get(network);
+
+ if (!api || !pApi || bondedPoolsSynced.current !== 'unsynced') {
return;
}
bondedPoolsSynced.current = 'syncing';
const ids: number[] = [];
- // Fetch bonded pools entries.
- const bondedPoolsMulti =
- await api.query.nominationPools.bondedPools.entries();
- let exposures = bondedPoolsMulti.map(([keys, val]: AnyApi) => {
- const id = keys.toHuman()[0];
- ids.push(id);
- return getPoolWithAddresses(id, val.toHuman());
- });
+ // Get and format bonded pool entries.
+ const bondedPoolsEntries = (
+ await new BondedPoolsEntries(pApi).fetch()
+ ).format();
+
+ let exposures = Object.entries(bondedPoolsEntries).map(
+ ([id, pool]: AnyApi) => {
+ ids.push(id);
+ return getPoolWithAddresses(id, pool);
+ }
+ );
exposures = shuffle(exposures);
setStateWithRef(exposures, setBondedPools, bondedPoolsRef);
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index 3b510d52e..56b6ce614 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -255,9 +255,7 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
let totalNonAllCommission = new BigNumber(0);
result.forEach(
({ keyArgs: [address], value: { commission, blocked } }: AnyApi) => {
- const commissionAsPercent = new BigNumber(
- perbillToPercent(new BigNumber(commission)).toString()
- );
+ const commissionAsPercent = perbillToPercent(commission);
if (!commissionAsPercent.isEqualTo(100)) {
totalNonAllCommission =
diff --git a/packages/app/src/library/Utils/index.ts b/packages/app/src/library/Utils/index.ts
index 8aa038460..40ef9a3f7 100644
--- a/packages/app/src/library/Utils/index.ts
+++ b/packages/app/src/library/Utils/index.ts
@@ -80,5 +80,11 @@ export const timeleftAsString = (
};
// Convert a perbill BigNumber value into a percentage.
-export const perbillToPercent = (value: BigNumber): BigNumber =>
- value.dividedBy('10000000');
+export const perbillToPercent = (
+ value: BigNumber | bigint | number
+): BigNumber => {
+ if (typeof value === 'bigint' || typeof value === 'number') {
+ value = new BigNumber(value.toString());
+ }
+ return value.dividedBy('10000000');
+};
diff --git a/packages/app/src/model/Query/BondedPoolsEntries/index.tsx b/packages/app/src/model/Query/BondedPoolsEntries/index.tsx
new file mode 100644
index 000000000..00bc867e8
--- /dev/null
+++ b/packages/app/src/model/Query/BondedPoolsEntries/index.tsx
@@ -0,0 +1,66 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import BigNumber from 'bignumber.js';
+import { perbillToPercent } from 'library/Utils';
+import type { PapiApi } from 'model/Api/types';
+import type { AnyApi } from 'types';
+
+export class BondedPoolsEntries {
+ #pApi: PapiApi;
+
+ bondedPools: AnyApi = {};
+
+ constructor(pApi: PapiApi) {
+ this.#pApi = pApi;
+ }
+
+ async fetch() {
+ this.bondedPools =
+ await this.#pApi.query.NominationPools.BondedPools.getEntries();
+ return this;
+ }
+
+ format() {
+ return Object.fromEntries(
+ this.bondedPools.map(
+ ({ keyArgs, value }: { keyArgs: [number]; value: AnyApi }) => {
+ const id = keyArgs[0];
+
+ const maybeCommissionCurrent = value.commission.current;
+ const commissionCurrent = !maybeCommissionCurrent
+ ? null
+ : [
+ perbillToPercent(maybeCommissionCurrent[0]).toString(),
+ maybeCommissionCurrent[1],
+ ];
+
+ const commissionMax = value.commission.max;
+ const commissionMaxPercent = !commissionMax
+ ? null
+ : perbillToPercent(new BigNumber(value.commission.max));
+
+ const commissionChangeRate = value.commission.change_rate;
+
+ const commission = {
+ current: commissionCurrent,
+ claimPermission: value.commission.claim_permission?.type || null,
+ max: commissionMaxPercent,
+ changeRate: commissionChangeRate || null,
+ throttleFrom: value.commission.throttle_from || null,
+ };
+
+ const pool = {
+ commission,
+ points: value.points.toString(),
+ memberCounter: value.member_counter.toString(),
+ roles: value.roles,
+ state: value.state.type,
+ };
+
+ return [id, pool];
+ }
+ )
+ );
+ }
+}
diff --git a/packages/app/src/model/Query/NetworkMeta/index.ts b/packages/app/src/model/Query/NetworkMeta/index.ts
index 917d3334d..f8e99dc2b 100644
--- a/packages/app/src/model/Query/NetworkMeta/index.ts
+++ b/packages/app/src/model/Query/NetworkMeta/index.ts
@@ -71,9 +71,9 @@ export class NetworkMeta {
]);
// Format globalMaxCommission from a perbill to a percent.
- const globalMaxCommissionAsPercent = perbillToPercent(
- new BigNumber(globalMaxCommission)
- );
+ const globalMaxCommissionAsPercent = !globalMaxCommission
+ ? new BigNumber(0)
+ : perbillToPercent(globalMaxCommission);
// Format max pool members to be a BigNumber, or null if it's not set.
const maxPoolMembers = maxPoolMembersRaw
From b80900199c249166faa91bbd12b2284a98a90ecb Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Sat, 16 Nov 2024 09:42:02 +0700
Subject: [PATCH 21/84] entries to own directory
---
packages/app/src/contexts/Pools/BondedPools/index.tsx | 6 ++----
.../app/src/contexts/Validators/ValidatorEntries/index.tsx | 4 ++--
.../BondedPoolsEntries => Entries/BondedPools}/index.tsx | 2 +-
.../{Query/ValidatorEntries => Entries/Validators}/index.ts | 2 +-
4 files changed, 6 insertions(+), 8 deletions(-)
rename packages/app/src/model/{Query/BondedPoolsEntries => Entries/BondedPools}/index.tsx (98%)
rename packages/app/src/model/{Query/ValidatorEntries => Entries/Validators}/index.ts (91%)
diff --git a/packages/app/src/contexts/Pools/BondedPools/index.tsx b/packages/app/src/contexts/Pools/BondedPools/index.tsx
index e089231cf..89ab2984d 100644
--- a/packages/app/src/contexts/Pools/BondedPools/index.tsx
+++ b/packages/app/src/contexts/Pools/BondedPools/index.tsx
@@ -23,7 +23,7 @@ import { useApi } from '../../Api';
import { defaultBondedPoolsContext } from './defaults';
import { useCreatePoolAccounts } from 'hooks/useCreatePoolAccounts';
import { SyncController } from 'controllers/Sync';
-import { BondedPoolsEntries } from 'model/Query/BondedPoolsEntries';
+import { BondedPools } from 'model/Entries/BondedPools';
import { ApiController } from 'controllers/Api';
export const BondedPoolsContext = createContext(
@@ -75,9 +75,7 @@ export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
const ids: number[] = [];
// Get and format bonded pool entries.
- const bondedPoolsEntries = (
- await new BondedPoolsEntries(pApi).fetch()
- ).format();
+ const bondedPoolsEntries = (await new BondedPools(pApi).fetch()).format();
let exposures = Object.entries(bondedPoolsEntries).map(
([id, pool]: AnyApi) => {
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index 56b6ce614..ac54c395c 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -33,7 +33,7 @@ import { getLocalEraValidators, setLocalEraValidators } from '../Utils';
import { useErasPerDay } from 'hooks/useErasPerDay';
import { IdentitiesController } from 'controllers/Identities';
import type { AnyJson, Sync } from '@w3ux/types';
-import { ValidatorEntries } from 'model/Query/ValidatorEntries';
+import { Validators } from 'model/Entries/Validators';
import { ApiController } from 'controllers/Api';
import { perbillToPercent } from 'library/Utils';
@@ -248,7 +248,7 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
}
const { pApi } = ApiController.get(network);
- const result = await new ValidatorEntries(pApi).fetch();
+ const result = await new Validators(pApi).fetch();
const entries: Validator[] = [];
let notFullCommissionCount = 0;
diff --git a/packages/app/src/model/Query/BondedPoolsEntries/index.tsx b/packages/app/src/model/Entries/BondedPools/index.tsx
similarity index 98%
rename from packages/app/src/model/Query/BondedPoolsEntries/index.tsx
rename to packages/app/src/model/Entries/BondedPools/index.tsx
index 00bc867e8..a6ae9466b 100644
--- a/packages/app/src/model/Query/BondedPoolsEntries/index.tsx
+++ b/packages/app/src/model/Entries/BondedPools/index.tsx
@@ -6,7 +6,7 @@ import { perbillToPercent } from 'library/Utils';
import type { PapiApi } from 'model/Api/types';
import type { AnyApi } from 'types';
-export class BondedPoolsEntries {
+export class BondedPools {
#pApi: PapiApi;
bondedPools: AnyApi = {};
diff --git a/packages/app/src/model/Query/ValidatorEntries/index.ts b/packages/app/src/model/Entries/Validators/index.ts
similarity index 91%
rename from packages/app/src/model/Query/ValidatorEntries/index.ts
rename to packages/app/src/model/Entries/Validators/index.ts
index 2c248b348..1f64955f5 100644
--- a/packages/app/src/model/Query/ValidatorEntries/index.ts
+++ b/packages/app/src/model/Entries/Validators/index.ts
@@ -3,7 +3,7 @@
import type { PapiApi } from 'model/Api/types';
-export class ValidatorEntries {
+export class Validators {
#pApi: PapiApi;
constructor(pApi: PapiApi) {
From 40fd03eccaa03635042cd9717afe8d4d819464af Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Sat, 16 Nov 2024 10:10:52 +0700
Subject: [PATCH 22/84] paged result fix
---
packages/app/src/contexts/Staking/index.tsx | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/packages/app/src/contexts/Staking/index.tsx b/packages/app/src/contexts/Staking/index.tsx
index 2ca9f5b1e..e1ff18150 100644
--- a/packages/app/src/contexts/Staking/index.tsx
+++ b/packages/app/src/contexts/Staking/index.tsx
@@ -245,12 +245,15 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
const result: Exposure[] = [];
let i = 0;
- for (const [
- {
+ // NOTE: Only one page is fetched for each validator for now.
+ for (const pages of pagedResults) {
+ const page = pages[0];
+
+ const {
keyArgs,
value: { others },
- },
- ] of pagedResults) {
+ } = page;
+
const validator = validatorKeys[i];
const { own, total } = validators[validator];
From c16369a81547b8c7fdfeb3a9ede5d97f25e5e341 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Sat, 16 Nov 2024 10:11:35 +0700
Subject: [PATCH 23/84] `Bonded` to subscription
---
packages/app/src/contexts/Bonded/index.tsx | 109 ++++++++----------
packages/app/src/contexts/Staking/index.tsx | 2 +-
.../src/controllers/Subscriptions/types.ts | 2 +
.../app/src/model/Subscribe/Bonded/index.tsx | 64 ++++++++++
packages/app/src/types.ts | 2 +
5 files changed, 114 insertions(+), 65 deletions(-)
create mode 100644 packages/app/src/model/Subscribe/Bonded/index.tsx
diff --git a/packages/app/src/contexts/Bonded/index.tsx b/packages/app/src/contexts/Bonded/index.tsx
index 8e1a9286c..ac7333ae6 100644
--- a/packages/app/src/contexts/Bonded/index.tsx
+++ b/packages/app/src/contexts/Bonded/index.tsx
@@ -1,7 +1,6 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
import {
addedTo,
matchedProperties,
@@ -9,9 +8,9 @@ import {
setStateWithRef,
} from '@w3ux/utils';
import type { ReactNode } from 'react';
-import { createContext, useContext, useEffect, useRef, useState } from 'react';
+import { createContext, useContext, useRef, useState } from 'react';
import { useApi } from 'contexts/Api';
-import type { AnyApi, MaybeAddress } from 'types';
+import type { MaybeAddress } from 'types';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import { useNetwork } from 'contexts/Network';
import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
@@ -19,6 +18,10 @@ import { useOtherAccounts } from 'contexts/Connect/OtherAccounts';
import { useExternalAccounts } from 'contexts/Connect/ExternalAccounts';
import * as defaults from './defaults';
import type { BondedAccount, BondedContextInterface } from './types';
+import { useEventListener } from 'usehooks-ts';
+import { isCustomEvent } from 'controllers/utils';
+import { SubscriptionsController } from 'controllers/Subscriptions';
+import { Bonded } from 'model/Subscribe/Bonded';
export const BondedContext = createContext(
defaults.defaultBondedContext
@@ -27,8 +30,8 @@ export const BondedContext = createContext(
export const useBonded = () => useContext(BondedContext);
export const BondedProvider = ({ children }: { children: ReactNode }) => {
+ const { isReady } = useApi();
const { network } = useNetwork();
- const { api, isReady } = useApi();
const { accounts } = useImportedAccounts();
const { addExternalAccount } = useExternalAccounts();
const { addOrReplaceOtherAccount } = useOtherAccounts();
@@ -37,8 +40,6 @@ export const BondedProvider = ({ children }: { children: ReactNode }) => {
const [bondedAccounts, setBondedAccounts] = useState([]);
const bondedAccountsRef = useRef(bondedAccounts);
- const unsubs = useRef>({});
-
// Handle the syncing of accounts on accounts change.
const handleSyncAccounts = () => {
// Sync removed accounts.
@@ -48,23 +49,21 @@ export const BondedProvider = ({ children }: { children: ReactNode }) => {
]).map(({ address }) => address);
removed?.forEach((address) => {
- const unsub = unsubs.current[address];
- if (unsub) {
- unsub();
- }
+ SubscriptionsController.remove(network, `bonded-${address}`);
});
-
- unsubs.current = Object.fromEntries(
- Object.entries(unsubs.current).filter(([key]) => !removed.includes(key))
- );
};
// Sync added accounts.
const handleAddedAccounts = () => {
const added = addedTo(accounts, bondedAccountsRef.current, ['address']);
if (added.length) {
- // Subscribe to all newly added accounts bonded and nominator status.
- added.map(({ address }) => subscribeToBondedAccount(address));
+ added.forEach(({ address }) =>
+ SubscriptionsController.set(
+ network,
+ `bonded-${address}`,
+ new Bonded(network, address)
+ )
+ );
}
};
@@ -76,58 +75,41 @@ export const BondedProvider = ({ children }: { children: ReactNode }) => {
bondedAccountsRef
);
};
+
handleRemovedAccounts();
handleAddedAccounts();
handleExistingAccounts();
};
- // Subscribe to account, get controller and nominations.
- const subscribeToBondedAccount = async (address: string) => {
- if (!api) {
- return undefined;
- }
+ const getBondedAccount = (address: MaybeAddress) =>
+ bondedAccountsRef.current.find((a) => a.address === address)?.bonded ||
+ null;
- const unsub = await api.queryMulti(
- [[api.query.staking.bonded, address]],
- async ([controller]) => {
- const newAccount: BondedAccount = {
- address,
- };
-
- // set account bonded (controller) or null
- let newController = controller.unwrapOr(null);
- newController =
- newController === null
- ? null
- : (newController.toHuman() as string | null);
- newAccount.bonded = newController;
-
- // add bonded (controller) account as external account if not presently imported
- if (newController) {
- if (accounts.find((s) => s.address === newController) === undefined) {
- const result = addExternalAccount(newController, 'system');
- if (result) {
- addOrReplaceOtherAccount(result.account, result.type);
- }
+ // Handle `polkadot-api` events.
+ const handleNewBondedAccount = (e: Event) => {
+ if (isCustomEvent(e)) {
+ const { account } = e.detail;
+ const { bonded, address } = account;
+
+ // Add bonded (controller) account as external account if not presently imported
+ if (bonded) {
+ if (accounts.find((s) => s.address === bonded) === undefined) {
+ const result = addExternalAccount(bonded, 'system');
+ if (result) {
+ addOrReplaceOtherAccount(result.account, result.type);
}
}
-
- // remove stale account if it's already in list.
- const newBonded = Object.values(bondedAccountsRef.current)
- .filter((a) => a.address !== address)
- .concat(newAccount);
-
- setStateWithRef(newBonded, setBondedAccounts, bondedAccountsRef);
}
- );
- unsubs.current[address] = unsub;
- return unsub;
- };
+ // Remove stale account if it's already in list.
+ const newBonded = Object.values(bondedAccountsRef.current)
+ .filter((a) => a.address !== address)
+ .concat(account);
- const getBondedAccount = (address: MaybeAddress) =>
- bondedAccountsRef.current.find((a) => a.address === address)?.bonded ||
- null;
+ // Update bonded accounts state.
+ setStateWithRef(newBonded, setBondedAccounts, bondedAccountsRef);
+ }
+ };
// Handle accounts sync on connected accounts change.
useEffectIgnoreInitial(() => {
@@ -136,14 +118,13 @@ export const BondedProvider = ({ children }: { children: ReactNode }) => {
}
}, [accounts, network, isReady]);
- // Unsubscribe from subscriptions on unmount.
- useEffect(
- () => () =>
- Object.values(unsubs.current).forEach((unsub) => {
- unsub();
- }),
- []
+ // Handle new bonded account events.
+ useEventListener(
+ 'new-bonded-account',
+ handleNewBondedAccount,
+ useRef(document)
);
+
return (
{
const result: Exposure[] = [];
let i = 0;
- // NOTE: Only one page is fetched for each validator for now.
for (const pages of pagedResults) {
+ // NOTE: Only one page is fetched for each validator for now.
const page = pages[0];
const {
diff --git a/packages/app/src/controllers/Subscriptions/types.ts b/packages/app/src/controllers/Subscriptions/types.ts
index c050a3fc7..afcf10324 100644
--- a/packages/app/src/controllers/Subscriptions/types.ts
+++ b/packages/app/src/controllers/Subscriptions/types.ts
@@ -3,6 +3,7 @@
import type { ActiveEra } from 'model/Subscribe/ActiveEra';
import type { BlockNumber } from 'model/Subscribe/BlockNumber';
+import type { Bonded } from 'model/Subscribe/Bonded';
import type { NetworkMetrics } from 'model/Subscribe/NetworkMetrics';
import type { PoolsConfig } from 'model/Subscribe/PoolsConfig';
import type { StakingMetrics } from 'model/Subscribe/StakingMetrics';
@@ -11,6 +12,7 @@ import type { StakingMetrics } from 'model/Subscribe/StakingMetrics';
export type Subscription =
| ActiveEra
| BlockNumber
+ | Bonded
| NetworkMetrics
| PoolsConfig
| StakingMetrics;
diff --git a/packages/app/src/model/Subscribe/Bonded/index.tsx b/packages/app/src/model/Subscribe/Bonded/index.tsx
new file mode 100644
index 000000000..7e96e7780
--- /dev/null
+++ b/packages/app/src/model/Subscribe/Bonded/index.tsx
@@ -0,0 +1,64 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { BondedAccount } from 'contexts/Bonded/types';
+import { ApiController } from 'controllers/Api';
+import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import type { Subscription } from 'rxjs';
+import type { NetworkName } from 'types';
+
+export class Bonded implements Unsubscribable {
+ // The associated network for this instance.
+ #network: NetworkName;
+
+ // The stash address.
+ #address: string;
+
+ // The bonded address.
+ bonded: string;
+
+ // Active subscription.
+ #sub: Subscription;
+
+ constructor(network: NetworkName, address: string) {
+ this.#network = network;
+ this.#address = address;
+ this.subscribe();
+ }
+
+ subscribe = async (): Promise => {
+ try {
+ const { pApi } = ApiController.get(this.#network);
+
+ if (pApi && this.#sub === undefined) {
+ const unsub = pApi.query.Staking.Bonded.watchValue(
+ this.#address
+ ).subscribe((controller) => {
+ const account: BondedAccount = {
+ address: this.#address,
+ bonded: controller || null,
+ };
+
+ // Send bonded account to UI.
+ document.dispatchEvent(
+ new CustomEvent('new-bonded-account', {
+ detail: {
+ account,
+ },
+ })
+ );
+ });
+ this.#sub = unsub;
+ }
+ } catch (e) {
+ // Subscription failed.
+ }
+ };
+
+ // Unsubscribe from class subscription.
+ unsubscribe = (): void => {
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
+ }
+ };
+}
diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts
index e909ff810..f27bb185b 100644
--- a/packages/app/src/types.ts
+++ b/packages/app/src/types.ts
@@ -20,6 +20,7 @@ import type { APIEventDetail, PapiReadyEvent } from 'model/Api/types';
import type { OnlineStatusEvent } from 'controllers/OnlineStatus/types';
import type { AnyJson } from '@w3ux/types';
import type { BlockNumberEventDetail } from 'model/Subscribe/BlockNumber/types';
+import type { BondedAccount } from 'contexts/Bonded/types';
declare global {
interface Window {
@@ -42,6 +43,7 @@ declare global {
stakingMetrics: APIStakingMetrics;
}>;
'new-active-pool': CustomEvent;
+ 'new-bonded-account': CustomEvent;
'new-sync-status': CustomEvent;
'new-external-account': CustomEvent<{ address: string }>;
'new-account-balance': CustomEvent;
From b1be4e34f49a24c29abf6e17a4ae38e8ae7184e0 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Sun, 17 Nov 2024 14:19:32 +0700
Subject: [PATCH 24/84] use `substrate-bindings` for pool address generation
---
.../src/hooks/useCreatePoolAccounts/index.tsx | 34 +++++++++----------
packages/consts/src/index.ts | 9 -----
2 files changed, 16 insertions(+), 27 deletions(-)
diff --git a/packages/app/src/hooks/useCreatePoolAccounts/index.tsx b/packages/app/src/hooks/useCreatePoolAccounts/index.tsx
index e3bdc79da..c7285010d 100644
--- a/packages/app/src/hooks/useCreatePoolAccounts/index.tsx
+++ b/packages/app/src/hooks/useCreatePoolAccounts/index.tsx
@@ -1,14 +1,17 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { bnToU8a, u8aConcat } from '@polkadot/util';
+import { bnToU8a, stringToU8a, u8aConcat } from '@polkadot/util';
import BigNumber from 'bignumber.js';
import { BN } from 'bn.js';
-import { EmptyH256, ModPrefix, U32Opts } from 'consts';
import { useApi } from 'contexts/Api';
+import { AccountId } from '@polkadot-api/substrate-bindings';
export const useCreatePoolAccounts = () => {
- const { api, consts } = useApi();
+ const {
+ consts,
+ chainSpecs: { ss58Format },
+ } = useApi();
const { poolsPalletId } = consts;
// Generates pool stash and reward accounts. Assumes `poolsPalletId` is synced.
@@ -21,21 +24,16 @@ export const useCreatePoolAccounts = () => {
};
const createAccount = (poolId: BigNumber, index: number): string => {
- if (!api) {
- return '';
- }
- return api.registry
- .createType(
- 'AccountId32',
- u8aConcat(
- ModPrefix,
- poolsPalletId,
- new Uint8Array([index]),
- bnToU8a(new BN(poolId.toString()), U32Opts),
- EmptyH256
- )
- )
- .toString();
+ const key = u8aConcat(
+ stringToU8a('modl'),
+ poolsPalletId,
+ new Uint8Array([index]),
+ bnToU8a(new BN(poolId.toString()), { bitLength: 32, isLe: true }),
+ new Uint8Array(32)
+ );
+
+ const codec = AccountId(ss58Format);
+ return codec.dec(key);
};
return createPoolAccounts;
diff --git a/packages/consts/src/index.ts b/packages/consts/src/index.ts
index 82fd0d258..92c9d1cd8 100644
--- a/packages/consts/src/index.ts
+++ b/packages/consts/src/index.ts
@@ -1,8 +1,6 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { stringToU8a } from '@polkadot/util';
-
/*
* Global Constants
*/
@@ -11,13 +9,6 @@ export const ManualSigners = ['ledger', 'vault', 'wallet_connect'];
export const DiscordSupportUrl = 'https://discord.gg/QY7CSSJm3D';
export const MailSupportAddress = 'staking@polkadot.cloud';
-/*
- * Byte Helpers
- */
-export const EmptyH256 = new Uint8Array(32);
-export const ModPrefix = stringToU8a('modl');
-export const U32Opts = { bitLength: 32, isLe: true };
-
/*
* Element Thresholds
*/
From 953392864d9c5d82380bbb374d801d070adec756 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 10:58:02 +0700
Subject: [PATCH 25/84] add `FastUnstakeConfig` subscription
---
.../app/src/contexts/FastUnstake/defaults.ts | 4 +-
.../app/src/contexts/FastUnstake/index.tsx | 68 ++++++++++---------
.../app/src/contexts/FastUnstake/types.ts | 7 +-
.../src/controllers/Subscriptions/types.ts | 2 +
.../src/modals/ManageFastUnstake/index.tsx | 4 +-
.../Subscribe/FastUnstakeConfig/index.ts | 57 ++++++++++++++++
.../Subscribe/FastUnstakeConfig/types.ts | 12 ++++
7 files changed, 115 insertions(+), 39 deletions(-)
create mode 100644 packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
create mode 100644 packages/app/src/model/Subscribe/FastUnstakeConfig/types.ts
diff --git a/packages/app/src/contexts/FastUnstake/defaults.ts b/packages/app/src/contexts/FastUnstake/defaults.ts
index 3002dce83..7b950e2c5 100644
--- a/packages/app/src/contexts/FastUnstake/defaults.ts
+++ b/packages/app/src/contexts/FastUnstake/defaults.ts
@@ -14,6 +14,6 @@ export const defaultFastUnstakeContext: FastUnstakeContextInterface = {
meta: defaultMeta,
isExposed: null,
queueDeposit: null,
- head: null,
- counterForQueue: null,
+ head: undefined,
+ counterForQueue: undefined,
};
diff --git a/packages/app/src/contexts/FastUnstake/index.tsx b/packages/app/src/contexts/FastUnstake/index.tsx
index 4d950c642..3f090454e 100644
--- a/packages/app/src/contexts/FastUnstake/index.tsx
+++ b/packages/app/src/contexts/FastUnstake/index.tsx
@@ -20,6 +20,11 @@ import type {
MetaInterface,
} from './types';
import type { AnyJson } from '@w3ux/types';
+import { SubscriptionsController } from 'controllers/Subscriptions';
+import { FastUnstakeConfig } from 'model/Subscribe/FastUnstakeConfig';
+import { useEventListener } from 'usehooks-ts';
+import { isCustomEvent } from 'controllers/utils';
+import type { FastUnstakeHead } from 'model/Subscribe/FastUnstakeConfig/types';
const worker = new Worker();
@@ -61,12 +66,10 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
const queueDepositRef = useRef(queueDeposit);
// store fastUnstake head.
- const [head, setHead] = useState(null);
- const headRef = useRef(head);
+ const [head, setHead] = useState();
// store fastUnstake counter for queue.
- const [counterForQueue, setCounterForQueue] = useState(null);
- const counterForQueueRef = useRef(counterForQueue);
+ const [counterForQueue, setCounterForQueue] = useState();
// store fastUnstake subscription unsub.
const unsubs = useRef([]);
@@ -77,11 +80,10 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
// check until bond duration eras surpasssed.
const checkToEra = activeEra.index.minus(bondDuration);
- // Reset state on network or active account change.
+ // Reset state on active account change.
useEffect(() => {
setStateWithRef(false, setChecking, checkingRef);
setStateWithRef(null, setqueueDeposit, queueDepositRef);
- setStateWithRef(null, setCounterForQueue, counterForQueueRef);
setStateWithRef(null, setIsExposed, isExposedRef);
setStateWithRef(defaultMeta, setMeta, metaRef);
unsubs.current = [];
@@ -90,9 +92,14 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
for (const unsub of unsubs.current) {
unsub();
}
+ }, [activeAccount]);
- // Resubscribe to fast unstake queue.
- }, [activeAccount, network]);
+ // Reset state on network change.
+ useEffect(() => {
+ setHead(undefined);
+ setCounterForQueue(undefined);
+ unsubs.current = [];
+ }, [network]);
// Subscribe to fast unstake queue as soon as api is ready.
useEffect(() => {
@@ -272,7 +279,7 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
return;
}
- // TODO: Make a `combineLatest` subscription with new event ----------------------
+ // TODO: Make a subscription with new event ----------------------
const subscribeQueue = async (a: MaybeAddress) => {
const u = await api.query.fastUnstake.queue(a, (q: AnyApi) =>
setStateWithRef(
@@ -283,32 +290,16 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
);
return u;
};
- const subscribeHead = async () => {
- const u = await api.query.fastUnstake.head((result: AnyApi) => {
- const h = result.unwrapOrDefault(null).toHuman();
- setStateWithRef(h, setHead, headRef);
- });
- return u;
- };
- const subscribeCounterForQueue = async () => {
- const u = await api.query.fastUnstake.counterForQueue(
- (result: AnyApi) => {
- const c = result.toHuman();
- setStateWithRef(c, setCounterForQueue, counterForQueueRef);
- }
- );
- return u;
- };
- // --------------------------------------------------------------------------------
+ // ----------------------------------------------------------------
- // Subscribe to queue + head.
+ SubscriptionsController.set(
+ network,
+ 'fastUnstakeMeta',
+ new FastUnstakeConfig(network)
+ );
// initiate subscription, add to unsubs.
- await Promise.all([
- subscribeQueue(activeAccount),
- subscribeHead(),
- subscribeCounterForQueue(),
- ]).then((u) => {
+ await Promise.all([subscribeQueue(activeAccount)]).then((u) => {
unsubs.current = u;
});
};
@@ -337,6 +328,19 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
return localMetaValidated;
};
+ // Handle fast unstake meta events.
+ const handleNewFastUnstakeData = (e: Event) => {
+ if (isCustomEvent(e)) {
+ const { head: eventHead, counterForQueue: eventCounterForQueue } =
+ e.detail;
+ setHead(eventHead);
+ setCounterForQueue(eventCounterForQueue);
+ }
+ };
+
+ const documentRef = useRef(document);
+ useEventListener('api-status', handleNewFastUnstakeData, documentRef);
+
return (
{
{t('fastUnstakeOnceRegistered')}
- {t('fastUnstakeCurrentQueue')}: {counterForQueue}
+ {t('fastUnstakeCurrentQueue')}: {counterForQueue || 0}
>
@@ -188,7 +188,7 @@ export const ManageFastUnstake = () => {
- {t('fastUnstakeCurrentQueue')}: {counterForQueue}
+ {t('fastUnstakeCurrentQueue')}: {counterForQueue || 0}
{t('fastUnstakeUnorderedNote')}
diff --git a/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
new file mode 100644
index 000000000..b6af21863
--- /dev/null
+++ b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
@@ -0,0 +1,57 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import { ApiController } from 'controllers/Api';
+import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import type { Subscription } from 'rxjs';
+import { combineLatest } from 'rxjs';
+import type { NetworkName } from 'types';
+import type { FastUnstakeConfigResult } from './types';
+
+export class FastUnstakeConfig implements Unsubscribable {
+ // The associated network for this instance.
+ #network: NetworkName;
+
+ // Active subscription.
+ #sub: Subscription;
+
+ constructor(network: NetworkName) {
+ this.#network = network;
+ this.subscribe();
+ }
+
+ subscribe = async (): Promise => {
+ try {
+ const { pApi } = ApiController.get(this.#network);
+
+ if (pApi && this.#sub === undefined) {
+ const sub = combineLatest([
+ pApi.query.FastUnstake.Head.watchValue(),
+ pApi.query.FastUnstake.CounterForQueue.watchValue(),
+ ]).subscribe(([head, counterForQueue]) => {
+ const data: FastUnstakeConfigResult = {
+ head,
+ counterForQueue,
+ };
+
+ document.dispatchEvent(
+ new CustomEvent('new-fast-unstake-data', {
+ detail: { data },
+ })
+ );
+ });
+
+ this.#sub = sub;
+ }
+ } catch (e) {
+ // Subscription failed.
+ }
+ };
+
+ // Unsubscribe from class subscription.
+ unsubscribe = (): void => {
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
+ }
+ };
+}
diff --git a/packages/app/src/model/Subscribe/FastUnstakeConfig/types.ts b/packages/app/src/model/Subscribe/FastUnstakeConfig/types.ts
new file mode 100644
index 000000000..8d64f3c59
--- /dev/null
+++ b/packages/app/src/model/Subscribe/FastUnstakeConfig/types.ts
@@ -0,0 +1,12 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+export interface FastUnstakeConfigResult {
+ head: FastUnstakeHead;
+ counterForQueue: number;
+}
+
+export interface FastUnstakeHead {
+ stashes: [string, bigint][];
+ checked: number[];
+}
From 40d9dbe7788747bf9848bb004d07699988944237 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 10:59:16 +0700
Subject: [PATCH 26/84] fix
---
packages/app/src/contexts/FastUnstake/index.tsx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/app/src/contexts/FastUnstake/index.tsx b/packages/app/src/contexts/FastUnstake/index.tsx
index 3f090454e..6f1c78fe4 100644
--- a/packages/app/src/contexts/FastUnstake/index.tsx
+++ b/packages/app/src/contexts/FastUnstake/index.tsx
@@ -339,7 +339,11 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
};
const documentRef = useRef(document);
- useEventListener('api-status', handleNewFastUnstakeData, documentRef);
+ useEventListener(
+ 'new-fast-unstake-data',
+ handleNewFastUnstakeData,
+ documentRef
+ );
return (
Date: Mon, 18 Nov 2024 10:59:34 +0700
Subject: [PATCH 27/84] add type
---
packages/app/src/types.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts
index f27bb185b..9472a4b96 100644
--- a/packages/app/src/types.ts
+++ b/packages/app/src/types.ts
@@ -21,6 +21,7 @@ import type { OnlineStatusEvent } from 'controllers/OnlineStatus/types';
import type { AnyJson } from '@w3ux/types';
import type { BlockNumberEventDetail } from 'model/Subscribe/BlockNumber/types';
import type { BondedAccount } from 'contexts/Bonded/types';
+import type { FastUnstakeConfigResult } from 'model/Subscribe/FastUnstakeConfig/types';
declare global {
interface Window {
@@ -43,6 +44,7 @@ declare global {
stakingMetrics: APIStakingMetrics;
}>;
'new-active-pool': CustomEvent;
+ 'new-fast-unstake-data': CustomEvent;
'new-bonded-account': CustomEvent;
'new-sync-status': CustomEvent;
'new-external-account': CustomEvent<{ address: string }>;
From 71cd4e53bc35f651bb17d75fcefd92c7a18f52c6 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 11:03:59 +0700
Subject: [PATCH 28/84] rename
---
packages/app/src/contexts/FastUnstake/index.tsx | 2 +-
packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts | 2 +-
packages/app/src/types.ts | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/app/src/contexts/FastUnstake/index.tsx b/packages/app/src/contexts/FastUnstake/index.tsx
index 6f1c78fe4..de5b7fda4 100644
--- a/packages/app/src/contexts/FastUnstake/index.tsx
+++ b/packages/app/src/contexts/FastUnstake/index.tsx
@@ -340,7 +340,7 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
const documentRef = useRef(document);
useEventListener(
- 'new-fast-unstake-data',
+ 'new-fast-unstake-config',
handleNewFastUnstakeData,
documentRef
);
diff --git a/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
index b6af21863..e3855f57f 100644
--- a/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
+++ b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
@@ -35,7 +35,7 @@ export class FastUnstakeConfig implements Unsubscribable {
};
document.dispatchEvent(
- new CustomEvent('new-fast-unstake-data', {
+ new CustomEvent('new-fast-unstake-config', {
detail: { data },
})
);
diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts
index 9472a4b96..77fe762ff 100644
--- a/packages/app/src/types.ts
+++ b/packages/app/src/types.ts
@@ -44,7 +44,7 @@ declare global {
stakingMetrics: APIStakingMetrics;
}>;
'new-active-pool': CustomEvent;
- 'new-fast-unstake-data': CustomEvent;
+ 'new-fast-unstake-config': CustomEvent;
'new-bonded-account': CustomEvent;
'new-sync-status': CustomEvent;
'new-external-account': CustomEvent<{ address: string }>;
From c11b18f9520c759463e90203096ebaac72a3f27b Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 11:06:45 +0700
Subject: [PATCH 29/84] polish
---
.../app/src/model/Subscribe/FastUnstakeConfig/index.ts | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
index e3855f57f..94237a35f 100644
--- a/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
+++ b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
@@ -15,6 +15,8 @@ export class FastUnstakeConfig implements Unsubscribable {
// Active subscription.
#sub: Subscription;
+ config: FastUnstakeConfigResult;
+
constructor(network: NetworkName) {
this.#network = network;
this.subscribe();
@@ -29,14 +31,16 @@ export class FastUnstakeConfig implements Unsubscribable {
pApi.query.FastUnstake.Head.watchValue(),
pApi.query.FastUnstake.CounterForQueue.watchValue(),
]).subscribe(([head, counterForQueue]) => {
- const data: FastUnstakeConfigResult = {
+ const config: FastUnstakeConfigResult = {
head,
counterForQueue,
};
+ this.config = config;
+
document.dispatchEvent(
new CustomEvent('new-fast-unstake-config', {
- detail: { data },
+ detail: { ...config },
})
);
});
From f65b7c7fe2daae6136cc793c0a6e990060ee5233 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 11:36:50 +0700
Subject: [PATCH 30/84] add `FastUnstakeQueue` subscription, rm from context
---
.../app/src/contexts/FastUnstake/defaults.ts | 2 +-
.../app/src/contexts/FastUnstake/index.tsx | 89 ++++++++-----------
.../app/src/contexts/FastUnstake/types.ts | 12 ++-
.../src/controllers/Subscriptions/types.ts | 2 +
packages/app/src/hooks/useUnstaking/index.tsx | 2 +-
.../model/Subscribe/FastUnstakeQueue/index.ts | 60 +++++++++++++
packages/app/src/types.ts | 2 +
7 files changed, 114 insertions(+), 55 deletions(-)
create mode 100644 packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts
diff --git a/packages/app/src/contexts/FastUnstake/defaults.ts b/packages/app/src/contexts/FastUnstake/defaults.ts
index 7b950e2c5..d1f39320c 100644
--- a/packages/app/src/contexts/FastUnstake/defaults.ts
+++ b/packages/app/src/contexts/FastUnstake/defaults.ts
@@ -13,7 +13,7 @@ export const defaultFastUnstakeContext: FastUnstakeContextInterface = {
checking: false,
meta: defaultMeta,
isExposed: null,
- queueDeposit: null,
head: undefined,
+ queueDeposit: undefined,
counterForQueue: undefined,
};
diff --git a/packages/app/src/contexts/FastUnstake/index.tsx b/packages/app/src/contexts/FastUnstake/index.tsx
index de5b7fda4..2d02f9d26 100644
--- a/packages/app/src/contexts/FastUnstake/index.tsx
+++ b/packages/app/src/contexts/FastUnstake/index.tsx
@@ -1,13 +1,13 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { rmCommas, setStateWithRef } from '@w3ux/utils';
+import { setStateWithRef } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import { createContext, useContext, useEffect, useRef, useState } from 'react';
import { useApi } from 'contexts/Api';
import { useStaking } from 'contexts/Staking';
-import type { AnyApi, MaybeAddress } from 'types';
+import type { MaybeAddress } from 'types';
import Worker from 'workers/stakers?worker';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import { validateLocalExposure } from 'contexts/Validators/Utils';
@@ -16,6 +16,7 @@ import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { defaultFastUnstakeContext, defaultMeta } from './defaults';
import type {
FastUnstakeContextInterface,
+ FastUnstakeQueueDeposit,
LocalMeta,
MetaInterface,
} from './types';
@@ -25,6 +26,8 @@ import { FastUnstakeConfig } from 'model/Subscribe/FastUnstakeConfig';
import { useEventListener } from 'usehooks-ts';
import { isCustomEvent } from 'controllers/utils';
import type { FastUnstakeHead } from 'model/Subscribe/FastUnstakeConfig/types';
+import { FastUnstakeQueue } from 'model/Subscribe/FastUnstakeQueue';
+import { ApiController } from 'controllers/Api';
const worker = new Worker();
@@ -39,7 +42,6 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
const { activeAccount } = useActiveAccounts();
const { inSetup, fetchEraStakers, isBonding } = useStaking();
const {
- api,
consts,
isReady,
activeEra,
@@ -62,8 +64,7 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
const metaRef = useRef(meta);
// store fastUnstake queue deposit for user.
- const [queueDeposit, setqueueDeposit] = useState(null);
- const queueDepositRef = useRef(queueDeposit);
+ const [queueDeposit, setQueueDeposit] = useState();
// store fastUnstake head.
const [head, setHead] = useState();
@@ -71,9 +72,6 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
// store fastUnstake counter for queue.
const [counterForQueue, setCounterForQueue] = useState();
- // store fastUnstake subscription unsub.
- const unsubs = useRef([]);
-
// localStorage key to fetch local metadata.
const getLocalkey = (a: MaybeAddress) => `${network}_fast_unstake_${a}`;
@@ -82,15 +80,21 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
// Reset state on active account change.
useEffect(() => {
+ // Reset fast unstake managment state.
+ setQueueDeposit(undefined);
setStateWithRef(false, setChecking, checkingRef);
- setStateWithRef(null, setqueueDeposit, queueDepositRef);
setStateWithRef(null, setIsExposed, isExposedRef);
setStateWithRef(defaultMeta, setMeta, metaRef);
- unsubs.current = [];
- // cancel fast unstake check on network change or account change.
- for (const unsub of unsubs.current) {
- unsub();
+ // Re-subscribe to fast unstake queue.
+ SubscriptionsController.remove(network, 'fastUnstakeQueue');
+
+ if (activeAccount) {
+ SubscriptionsController.set(
+ network,
+ 'fastUnstakeQueue',
+ new FastUnstakeQueue(network, activeAccount)
+ );
}
}, [activeAccount]);
@@ -98,13 +102,12 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
useEffect(() => {
setHead(undefined);
setCounterForQueue(undefined);
- unsubs.current = [];
}, [network]);
// Subscribe to fast unstake queue as soon as api is ready.
useEffect(() => {
if (isReady) {
- subscribeToFastUnstakeQueue();
+ subscribeToFastUnstakeMeta();
}
}, [isReady]);
@@ -159,12 +162,6 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
processEligibility(activeAccount, maybeNextEra);
}
}
-
- return () => {
- for (const unsub of unsubs.current) {
- unsub();
- }
- };
}, [
inSetup(),
isReady,
@@ -218,7 +215,6 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
if (exposed) {
// Account is exposed - stop checking.
-
// cancel checking and update exposed state.
setStateWithRef(false, setChecking, checkingRef);
setStateWithRef(true, setIsExposed, isExposedRef);
@@ -226,9 +222,8 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
// successfully checked current era - bondDuration eras.
setStateWithRef(false, setChecking, checkingRef);
setStateWithRef(false, setIsExposed, isExposedRef);
-
- // Finished, not exposed.
} else {
+ // Finished, not exposed.
// continue checking the next era.
checkEra(new BigNumber(era).minus(1));
}
@@ -241,7 +236,6 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
if (
era.isLessThan(0) ||
!bondDuration.isGreaterThan(0) ||
- !api ||
!a ||
checkingRef.current ||
!activeAccount ||
@@ -256,10 +250,6 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
// calls service worker to check exppsures for given era.
const checkEra = async (era: BigNumber) => {
- if (!api) {
- return;
- }
-
const exposures = await fetchEraStakers(era.toString());
worker.postMessage({
@@ -274,34 +264,16 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
};
// subscribe to fastUnstake queue
- const subscribeToFastUnstakeQueue = async () => {
- if (!api) {
+ const subscribeToFastUnstakeMeta = async () => {
+ const { pApi } = await ApiController.get(network);
+ if (!pApi) {
return;
}
-
- // TODO: Make a subscription with new event ----------------------
- const subscribeQueue = async (a: MaybeAddress) => {
- const u = await api.query.fastUnstake.queue(a, (q: AnyApi) =>
- setStateWithRef(
- new BigNumber(rmCommas(q.unwrapOrDefault(0).toString())),
- setqueueDeposit,
- queueDepositRef
- )
- );
- return u;
- };
- // ----------------------------------------------------------------
-
SubscriptionsController.set(
network,
'fastUnstakeMeta',
new FastUnstakeConfig(network)
);
-
- // initiate subscription, add to unsubs.
- await Promise.all([subscribeQueue(activeAccount)]).then((u) => {
- unsubs.current = u;
- });
};
// gets any existing fast unstake metadata for an account.
@@ -329,7 +301,7 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
};
// Handle fast unstake meta events.
- const handleNewFastUnstakeData = (e: Event) => {
+ const handleNewFastUnstakeConfig = (e: Event) => {
if (isCustomEvent(e)) {
const { head: eventHead, counterForQueue: eventCounterForQueue } =
e.detail;
@@ -338,10 +310,23 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
}
};
+ // Handle fast unstake deposit events.
+ const handleNewFastUnstakeDeposit = (e: Event) => {
+ if (isCustomEvent(e)) {
+ const { address, deposit } = e.detail;
+ setQueueDeposit({ address, deposit: new BigNumber(deposit.toString()) });
+ }
+ };
+
const documentRef = useRef(document);
useEventListener(
'new-fast-unstake-config',
- handleNewFastUnstakeData,
+ handleNewFastUnstakeConfig,
+ documentRef
+ );
+ useEventListener(
+ 'new-fast-unstake-deposit',
+ handleNewFastUnstakeDeposit,
documentRef
);
diff --git a/packages/app/src/contexts/FastUnstake/types.ts b/packages/app/src/contexts/FastUnstake/types.ts
index bf9c4c556..345808b4a 100644
--- a/packages/app/src/contexts/FastUnstake/types.ts
+++ b/packages/app/src/contexts/FastUnstake/types.ts
@@ -18,7 +18,17 @@ export interface FastUnstakeContextInterface {
checking: boolean;
meta: MetaInterface;
isExposed: boolean | null;
- queueDeposit: BigNumber | null;
+ queueDeposit: FastUnstakeQueueDeposit | undefined;
head: FastUnstakeHead | undefined;
counterForQueue: number | undefined;
}
+
+export interface FastUnstakeQueueDeposit {
+ address: string;
+ deposit: BigNumber;
+}
+
+export interface FastUnstakeQueueResult {
+ address: string;
+ deposit: bigint;
+}
diff --git a/packages/app/src/controllers/Subscriptions/types.ts b/packages/app/src/controllers/Subscriptions/types.ts
index 91b94446a..d835634a5 100644
--- a/packages/app/src/controllers/Subscriptions/types.ts
+++ b/packages/app/src/controllers/Subscriptions/types.ts
@@ -5,6 +5,7 @@ import type { ActiveEra } from 'model/Subscribe/ActiveEra';
import type { BlockNumber } from 'model/Subscribe/BlockNumber';
import type { Bonded } from 'model/Subscribe/Bonded';
import type { FastUnstakeConfig } from 'model/Subscribe/FastUnstakeConfig';
+import type { FastUnstakeQueue } from 'model/Subscribe/FastUnstakeQueue';
import type { NetworkMetrics } from 'model/Subscribe/NetworkMetrics';
import type { PoolsConfig } from 'model/Subscribe/PoolsConfig';
import type { StakingMetrics } from 'model/Subscribe/StakingMetrics';
@@ -15,6 +16,7 @@ export type Subscription =
| BlockNumber
| Bonded
| FastUnstakeConfig
+ | FastUnstakeQueue
| NetworkMetrics
| PoolsConfig
| StakingMetrics;
diff --git a/packages/app/src/hooks/useUnstaking/index.tsx b/packages/app/src/hooks/useUnstaking/index.tsx
index 3a245cff0..5980cf16a 100644
--- a/packages/app/src/hooks/useUnstaking/index.tsx
+++ b/packages/app/src/hooks/useUnstaking/index.tsx
@@ -28,7 +28,7 @@ export const useUnstaking = () => {
// determine if user is fast unstaking.
const inHead =
head?.stashes.find((s: AnyJson) => s[0] === activeAccount) ?? undefined;
- const inQueue = queueDeposit?.isGreaterThan(0) ?? false;
+ const inQueue = queueDeposit?.deposit?.isGreaterThan(0) ?? false;
const registered = inHead || inQueue;
diff --git a/packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts b/packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts
new file mode 100644
index 000000000..156b4e2a4
--- /dev/null
+++ b/packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts
@@ -0,0 +1,60 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import { ApiController } from 'controllers/Api';
+import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import type { Subscription } from 'rxjs';
+import type { NetworkName } from 'types';
+
+export class FastUnstakeQueue implements Unsubscribable {
+ // The associated network for this instance.
+ #network: NetworkName;
+
+ // The depositor address.
+ #address: string;
+
+ // The deposit.
+ queue: bigint;
+
+ // Active subscription.
+ #sub: Subscription;
+
+ constructor(network: NetworkName, address: string) {
+ this.#network = network;
+ this.#address = address;
+ this.subscribe();
+ }
+
+ subscribe = async (): Promise => {
+ try {
+ const { pApi } = ApiController.get(this.#network);
+
+ if (pApi && this.#sub === undefined) {
+ const unsub = pApi.query.FastUnstake.Queue.watchValue(
+ this.#address
+ ).subscribe((queue) => {
+ this.queue = queue;
+
+ document.dispatchEvent(
+ new CustomEvent('new-fast-unstake-deposit', {
+ detail: {
+ address: this.#address,
+ deposit: queue || 0n,
+ },
+ })
+ );
+ });
+ this.#sub = unsub;
+ }
+ } catch (e) {
+ // Subscription failed.
+ }
+ };
+
+ // Unsubscribe from class subscription.
+ unsubscribe = (): void => {
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
+ }
+ };
+}
diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts
index 77fe762ff..1651a9343 100644
--- a/packages/app/src/types.ts
+++ b/packages/app/src/types.ts
@@ -22,6 +22,7 @@ import type { AnyJson } from '@w3ux/types';
import type { BlockNumberEventDetail } from 'model/Subscribe/BlockNumber/types';
import type { BondedAccount } from 'contexts/Bonded/types';
import type { FastUnstakeConfigResult } from 'model/Subscribe/FastUnstakeConfig/types';
+import type { FastUnstakeQueueResult } from 'contexts/FastUnstake/types';
declare global {
interface Window {
@@ -45,6 +46,7 @@ declare global {
}>;
'new-active-pool': CustomEvent;
'new-fast-unstake-config': CustomEvent;
+ 'new-fast-unstake-deposit': CustomEvent;
'new-bonded-account': CustomEvent;
'new-sync-status': CustomEvent;
'new-external-account': CustomEvent<{ address: string }>;
From 969409c247b6f4bc0b3a8257225c18d406cd1b3d Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 11:38:42 +0700
Subject: [PATCH 31/84] rm log
---
packages/app/src/model/Api/index.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index f8c15e9d4..d65f6088f 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -206,7 +206,6 @@ export class Api {
// Dispatch 'papi-ready' event to let contexts populate constants.
this.dispatchPapiReadyEvent();
} catch (e) {
- console.debug('PAPI chain spec failed');
// TODO: Expand this when PJS API has been removed. Flag an error if there are any issues
// bootstrapping chain spec. NOTE: This can happen when PAPI is the standalone connection
// method.
From 2af9b149349ef3c812d05d521cc2fa97a3b2f24c Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 14:03:25 +0700
Subject: [PATCH 32/84] Abstract balances to `AccountBalances` subscription
---
packages/app/src/contexts/Balances/index.tsx | 10 +-
packages/app/src/contexts/Balances/types.ts | 6 +-
.../Connect/ImportedAccounts/index.tsx | 3 +-
.../app/src/contexts/FastUnstake/index.tsx | 2 +-
.../app/src/controllers/Balances/index.ts | 304 ++----------------
.../src/controllers/Subscriptions/types.ts | 2 +
.../app/src/hooks/useActiveBalances/index.tsx | 5 +-
.../model/Subscribe/AccountBalances/index.ts | 232 +++++++++++++
8 files changed, 285 insertions(+), 279 deletions(-)
create mode 100644 packages/app/src/model/Subscribe/AccountBalances/index.ts
diff --git a/packages/app/src/contexts/Balances/index.tsx b/packages/app/src/contexts/Balances/index.tsx
index 110b8dfed..ab8087b0a 100644
--- a/packages/app/src/contexts/Balances/index.tsx
+++ b/packages/app/src/contexts/Balances/index.tsx
@@ -17,6 +17,7 @@ import { SyncController } from 'controllers/Sync';
import { useApi } from 'contexts/Api';
import { ActivePoolsController } from 'controllers/ActivePools';
import { useCreatePoolAccounts } from 'hooks/useCreatePoolAccounts';
+import { useNetwork } from 'contexts/Network';
export const BalancesContext = createContext(
defaults.defaultBalancesContext
@@ -25,6 +26,7 @@ export const BalancesContext = createContext(
export const useBalances = () => useContext(BalancesContext);
export const BalancesProvider = ({ children }: { children: ReactNode }) => {
+ const { network } = useNetwork();
const { getBondedAccount } = useBonded();
const { accounts } = useImportedAccounts();
const createPoolAccounts = useCreatePoolAccounts();
@@ -82,7 +84,7 @@ export const BalancesProvider = ({ children }: { children: ReactNode }) => {
// Check whether all accounts have been synced and update state accordingly.
const checkBalancesSynced = () => {
- if (Object.keys(BalancesController.balances).length === accounts.length) {
+ if (Object.keys(BalancesController.accounts).length === accounts.length) {
SyncController.dispatch('balances', 'complete');
}
};
@@ -91,7 +93,11 @@ export const BalancesProvider = ({ children }: { children: ReactNode }) => {
// payload.
const getNonce = (address: MaybeAddress) => {
if (address) {
- const maybeNonce = BalancesController.balances[address]?.nonce;
+ const accountBalances = BalancesController.getAccountBalances(
+ network,
+ address
+ );
+ const maybeNonce = accountBalances?.balances?.nonce;
if (maybeNonce) {
return maybeNonce;
}
diff --git a/packages/app/src/contexts/Balances/types.ts b/packages/app/src/contexts/Balances/types.ts
index 66fd06ff0..3031e8dd3 100644
--- a/packages/app/src/contexts/Balances/types.ts
+++ b/packages/app/src/contexts/Balances/types.ts
@@ -20,10 +20,10 @@ export interface BalancesContextInterface {
export type ActiveBalancesState = Record;
export interface ActiveBalance {
- ledger: Ledger;
+ ledger: Ledger | undefined;
balances: Balances;
- payee: PayeeConfig;
- poolMembership: PoolMembership;
+ payee: PayeeConfig | undefined;
+ poolMembership: PoolMembership | undefined;
nominations: Nominations;
}
diff --git a/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx b/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx
index 9c837f77e..bac80eb17 100644
--- a/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx
+++ b/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx
@@ -40,7 +40,6 @@ export const ImportedAccountsProvider = ({
const { otherAccounts } = useOtherAccounts();
const { getExtensionAccounts } = useExtensionAccounts();
const { setActiveAccount, setActiveProxy } = useActiveAccounts();
-
// Get the imported extension accounts formatted with the current network's ss58 prefix.
const extensionAccounts = getExtensionAccounts(ss58);
@@ -118,7 +117,7 @@ export const ImportedAccountsProvider = ({
useEffectIgnoreInitial(() => {
if (api && isReady) {
BalancesController.syncAccounts(
- api,
+ network,
allAccounts.map((a) => a.address)
);
}
diff --git a/packages/app/src/contexts/FastUnstake/index.tsx b/packages/app/src/contexts/FastUnstake/index.tsx
index 2d02f9d26..76f0627f3 100644
--- a/packages/app/src/contexts/FastUnstake/index.tsx
+++ b/packages/app/src/contexts/FastUnstake/index.tsx
@@ -265,7 +265,7 @@ export const FastUnstakeProvider = ({ children }: { children: ReactNode }) => {
// subscribe to fastUnstake queue
const subscribeToFastUnstakeMeta = async () => {
- const { pApi } = await ApiController.get(network);
+ const { pApi } = ApiController.get(network);
if (!pApi) {
return;
}
diff --git a/packages/app/src/controllers/Balances/index.ts b/packages/app/src/controllers/Balances/index.ts
index df8086d5f..3010ef2f2 100644
--- a/packages/app/src/controllers/Balances/index.ts
+++ b/packages/app/src/controllers/Balances/index.ts
@@ -1,61 +1,23 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { rmCommas } from '@w3ux/utils';
-import BigNumber from 'bignumber.js';
-import type { AnyApi, MaybeAddress } from 'types';
-import type {
- ActiveBalance,
- Balances,
- Ledger,
- Nominations,
- UnlockChunkRaw,
-} from 'contexts/Balances/types';
-import type { PayeeConfig, PayeeOptions } from 'contexts/Setup/types';
-import type { PoolMembership } from 'contexts/Pools/types';
+import type { NetworkName } from 'types';
+import type { ActiveBalance } from 'contexts/Balances/types';
import { SyncController } from 'controllers/Sync';
-import { defaultNominations } from './defaults';
-import type { VoidFn } from '@polkadot/api/types';
-import type { ApiPromise } from '@polkadot/api';
-import { stringToBn } from 'library/Utils';
+import { SubscriptionsController } from 'controllers/Subscriptions';
+import { AccountBalances } from 'model/Subscribe/AccountBalances';
export class BalancesController {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// Accounts that are being subscribed to.
static accounts: string[] = [];
- // Account ledgers, populated by api callbacks.
- static ledgers: Record = {};
-
- // Account balances, populated by api callbacks.
- static balances: Record = {};
-
- // Account payees, populated by api callbacks.
- static payees: Record = {};
-
- // Account pool membership and claim commissions, populated by api callbacks.
- static poolMemberships: Record = {};
-
- // Account nominations, populated by api callbacks.
- static nominations: Record = {};
-
- // Unsubscribe objects.
- static #unsubs: Record = {};
-
- // ------------------------------------------------------
- // Account syncing.
- // ------------------------------------------------------
-
// Subscribes new accounts and unsubscribes & removes removed accounts.
static syncAccounts = async (
- api: ApiPromise,
+ network: NetworkName,
newAccounts: string[]
): Promise => {
// Handle accounts that have been removed.
- this.handleRemovedAccounts(newAccounts);
+ this.handleRemovedAccounts(network, newAccounts);
// Determine new accounts that need to be subscribed to.
const accountsAdded = newAccounts.filter(
@@ -73,237 +35,55 @@ export class BalancesController {
// Subscribe to and add new accounts data.
accountsAdded.forEach(async (address) => {
this.accounts.push(address);
- const unsub = await api.queryMulti(
- [
- [api.query.staking.ledger, address],
- [api.query.system.account, address],
- [api.query.balances.locks, address],
- [api.query.staking.payee, address],
- [api.query.nominationPools.poolMembers, address],
- [api.query.nominationPools.claimPermissions, address],
- [api.query.staking.nominators, address],
- ],
- async ([
- ledgerResult,
- accountResult,
- locksResult,
- payeeResult,
- poolMembersResult,
- claimPermissionsResult,
- nominatorsResult,
- ]): Promise => {
- this.handleLedgerCallback(address, ledgerResult);
- this.handleAccountCallback(address, accountResult, locksResult);
- this.handlePayeeCallback(address, payeeResult);
-
- // NOTE: async: contains runtime call for pending rewards.
- await this.handlePoolMembershipCallback(
- api,
- address,
- poolMembersResult,
- claimPermissionsResult
- );
- this.handleNominations(address, nominatorsResult);
-
- // Send updated account state back to UI.
- document.dispatchEvent(
- new CustomEvent('new-account-balance', {
- detail: {
- address,
- ledger: this.ledgers[address],
- balances: this.balances[address],
- payee: this.payees[address],
- poolMembership: this.poolMemberships[address],
- nominations: this.nominations[address],
- },
- })
- );
- }
+ SubscriptionsController.set(
+ network,
+ `accountBalances-${address}`,
+ new AccountBalances(network, address)
);
- this.#unsubs[address] = unsub;
});
};
// Remove accounts that no longer exist.
- static handleRemovedAccounts = (newAccounts: string[]): void => {
+ static handleRemovedAccounts = (
+ network: NetworkName,
+ newAccounts: string[]
+ ): void => {
// Determine removed accounts.
const accountsRemoved = this.accounts.filter(
(account) => !newAccounts.includes(account)
);
// Unsubscribe from removed account subscriptions.
accountsRemoved.forEach((account) => {
- if (this.#unsubs[account]) {
- this.#unsubs[account]();
- }
- delete this.#unsubs[account];
- delete this.ledgers[account];
- delete this.balances[account];
- delete this.payees[account];
- delete this.poolMemberships[account];
- delete this.nominations[account];
+ SubscriptionsController.remove(network, `accountBalances-${account}`);
});
+
// Remove removed accounts from class.
this.accounts = this.accounts.filter(
(account) => !accountsRemoved.includes(account)
);
};
- // Handle ledger callback.
- static handleLedgerCallback = (address: string, result: AnyApi): void => {
- const ledger = result.unwrapOr(null);
-
- // If ledger is null, remove from class data and exit early.
- if (ledger === null) {
- delete this.ledgers[address];
- return;
- }
-
- const { stash, total, active, unlocking } = ledger;
-
- // Send stash address to UI as event if not presently imported.
- if (!this.accounts.includes(stash.toString())) {
- document.dispatchEvent(
- new CustomEvent('new-external-account', {
- detail: { address: stash.toString() },
- })
- );
- }
-
- this.ledgers[address] = {
- stash: stash.toString(),
- active: stringToBn(active.toString()),
- total: stringToBn(total.toString()),
- unlocking: unlocking.toHuman().map(({ era, value }: UnlockChunkRaw) => ({
- era: Number(rmCommas(era)),
- value: stringToBn(value),
- })),
- };
- };
-
- // Handle account callback.
- static handleAccountCallback = (
- address: string,
- { data: accountData, nonce }: AnyApi,
- locksResult: AnyApi
- ): void => {
- this.balances[address] = {
- nonce: nonce.toNumber(),
- balance: {
- free: stringToBn(accountData.free.toString()),
- reserved: stringToBn(accountData.reserved.toString()),
- frozen: stringToBn(accountData.frozen.toString()),
- },
- locks: locksResult
- .toHuman()
- .map((lock: { id: string; amount: string }) => ({
- ...lock,
- id: lock.id.trim(),
- amount: stringToBn(lock.amount),
- })),
- };
- };
-
- // Handle payee callback. payee with `Account` type is returned as an key value pair, with all
- // others strings. This function handles both cases and formats into a unified structure.
- static handlePayeeCallback = (address: string, result: AnyApi): void => {
- const payeeHuman = result.toHuman();
- let payeeFinal: PayeeConfig;
-
- if (payeeHuman !== null) {
- if (typeof payeeHuman === 'string') {
- const destination = payeeHuman as PayeeOptions;
- payeeFinal = {
- destination,
- account: null,
- };
- } else {
- const payeeEntry = Object.entries(payeeHuman);
- const destination = `${payeeEntry[0][0]}` as PayeeOptions;
- const account = `${payeeEntry[0][1]}` as MaybeAddress;
- payeeFinal = {
- destination,
- account,
- };
- }
- this.payees[address] = payeeFinal;
- }
- };
-
- // Handle pool membership and claim commission callback.
- static handlePoolMembershipCallback = async (
- api: ApiPromise,
- address: string,
- poolMembersResult: AnyApi,
- claimPermissionsResult: AnyApi
- ): Promise => {
- // If pool membership is `null`, remove pool membership data from class data and exit early.
- // This skips claim permission data as well as user would not have claim permissions if they are
- // not in a pool.
- const membership = poolMembersResult?.unwrapOr(undefined)?.toHuman();
- if (!membership) {
- delete this.poolMemberships[address];
- return;
- }
-
- // Format pool membership data.
- const unlocking = Object.entries(membership?.unbondingEras || {}).map(
- ([e, v]) => ({
- era: Number(rmCommas(e as string)),
- value: new BigNumber(rmCommas(v as string)),
- })
- );
- membership.points = rmCommas(membership?.points || '0');
- const balance = new BigNumber(
- (
- await api.call.nominationPoolsApi.pointsToBalance(
- membership.poolId,
- membership.points
- )
- )?.toString() || '0'
- );
- const claimPermission =
- claimPermissionsResult?.toString() || 'Permissioned';
-
- // Persist formatted pool membership data to class.
- this.poolMemberships[address] = {
- ...membership,
- address,
- balance,
- claimPermission,
- unlocking,
- };
- };
-
- // Handle nominations callback.
- static handleNominations = (
- address: string,
- nominatorsResult: AnyApi
- ): void => {
- const nominators = nominatorsResult.unwrapOr(null);
-
- this.nominations[address] =
- nominators === null
- ? defaultNominations
- : {
- targets: nominators.targets.toHuman(),
- submittedIn: nominators.submittedIn.toHuman(),
- };
- };
-
- // Gets an `ActiveBalance` from class members for the given address if it exists.
- static getAccountBalances = (address: string): ActiveBalance | undefined => {
- const ledger = this.ledgers[address];
- const balances = this.balances[address];
- const payee = this.payees[address];
- const poolMembership = this.poolMemberships[address];
- const nominations = this.nominations[address];
-
- if (balances === undefined) {
- // Account info has not synced yet. Note that `ledger` may not exist and therefore cannot be
- // tested.
+ // Gets an `AccountBalances` subscription from class members for the given address if it exists.
+ static getAccountBalances = (
+ network: NetworkName,
+ address: string
+ ): ActiveBalance | undefined => {
+ const accountBalances = SubscriptionsController.get(
+ network,
+ `accountBalances-${address}`
+ ) as AccountBalances;
+
+ // Account info has not synced yet - exit early.
+ if (!accountBalances) {
return undefined;
}
+ const ledger = accountBalances.ledger;
+ const balances = accountBalances.balance;
+ const payee = accountBalances.payee;
+ const poolMembership = accountBalances.poolMembership;
+ const nominations = accountBalances.nominations;
+
return {
ledger,
balances,
@@ -313,22 +93,6 @@ export class BalancesController {
};
};
- // ------------------------------------------------------
- // Subscription handling.
- // ------------------------------------------------------
-
- // Unsubscribe from all subscriptions and reset class members.
- static unsubscribe = (): void => {
- Object.values(this.#unsubs).forEach((unsub) => {
- unsub();
- });
- this.#unsubs = {};
- };
-
- // ------------------------------------------------------
- // Class helpers.
- // ------------------------------------------------------
-
// Checks if event detailis a valid `new-account-balance` event. Note that `ledger` may not exist
// and therefore cannot be tested.
static isValidNewAccountBalanceEvent = (
diff --git a/packages/app/src/controllers/Subscriptions/types.ts b/packages/app/src/controllers/Subscriptions/types.ts
index d835634a5..bff570d7e 100644
--- a/packages/app/src/controllers/Subscriptions/types.ts
+++ b/packages/app/src/controllers/Subscriptions/types.ts
@@ -1,6 +1,7 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
+import type { AccountBalances } from 'model/Subscribe/AccountBalances';
import type { ActiveEra } from 'model/Subscribe/ActiveEra';
import type { BlockNumber } from 'model/Subscribe/BlockNumber';
import type { Bonded } from 'model/Subscribe/Bonded';
@@ -12,6 +13,7 @@ import type { StakingMetrics } from 'model/Subscribe/StakingMetrics';
// Define all possible subscription classes.
export type Subscription =
+ | AccountBalances
| ActiveEra
| BlockNumber
| Bonded
diff --git a/packages/app/src/hooks/useActiveBalances/index.tsx b/packages/app/src/hooks/useActiveBalances/index.tsx
index 912dd890c..491bfe47c 100644
--- a/packages/app/src/hooks/useActiveBalances/index.tsx
+++ b/packages/app/src/hooks/useActiveBalances/index.tsx
@@ -170,7 +170,10 @@ export const useActiveBalances = ({
for (const account of uniqueAccounts) {
// Adds an active balance record if it exists in `BalancesController`.
if (account) {
- const accountBalances = BalancesController.getAccountBalances(account);
+ const accountBalances = BalancesController.getAccountBalances(
+ network,
+ account
+ );
if (accountBalances) {
newActiveBalances[account] = accountBalances;
}
diff --git a/packages/app/src/model/Subscribe/AccountBalances/index.ts b/packages/app/src/model/Subscribe/AccountBalances/index.ts
new file mode 100644
index 000000000..d9ecc7684
--- /dev/null
+++ b/packages/app/src/model/Subscribe/AccountBalances/index.ts
@@ -0,0 +1,232 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import BigNumber from 'bignumber.js';
+import type { Balances, Ledger, Nominations } from 'contexts/Balances/types';
+import type { PoolMembership } from 'contexts/Pools/types';
+import type { PayeeConfig } from 'contexts/Setup/types';
+import { ApiController } from 'controllers/Api';
+import { BalancesController } from 'controllers/Balances';
+import { defaultNominations } from 'controllers/Balances/defaults';
+import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import { stringToBn } from 'library/Utils';
+import type { PapiApi } from 'model/Api/types';
+import type { Subscription } from 'rxjs';
+import { combineLatest } from 'rxjs';
+import type { AnyApi, NetworkName } from 'types';
+
+export class AccountBalances implements Unsubscribable {
+ // The associated network for this instance.
+ #network: NetworkName;
+
+ // Active subscription.
+ #sub: Subscription;
+
+ // Account to subscribe to.
+ #address: string;
+
+ // Account ledger.
+ ledger: Ledger | undefined;
+
+ // Account balances.
+ balance: Balances;
+
+ // Payee config.
+ payee: PayeeConfig | undefined;
+
+ // Pool membership.
+ poolMembership: PoolMembership | undefined;
+
+ // Account nominations.
+ nominations: Nominations;
+
+ constructor(network: NetworkName, address: string) {
+ this.#network = network;
+ this.#address = address;
+ this.subscribe();
+ }
+
+ subscribe = async (): Promise => {
+ try {
+ const { pApi } = ApiController.get(this.#network);
+ const bestOrFinalized = 'best';
+
+ if (pApi && this.#sub === undefined) {
+ const sub = combineLatest([
+ pApi.query.Staking.Ledger.watchValue(this.#address, bestOrFinalized),
+ pApi.query.System.Account.watchValue(this.#address, bestOrFinalized),
+ pApi.query.Balances.Locks.watchValue(this.#address, bestOrFinalized),
+ pApi.query.Staking.Payee.watchValue(this.#address, bestOrFinalized),
+ pApi.query.NominationPools.PoolMembers.watchValue(
+ this.#address,
+ bestOrFinalized
+ ),
+ pApi.query.NominationPools.ClaimPermissions.watchValue(
+ this.#address,
+ bestOrFinalized
+ ),
+ pApi.query.Staking.Nominators.watchValue(
+ this.#address,
+ bestOrFinalized
+ ),
+ ]).subscribe(
+ async ([
+ ledger,
+ account,
+ locks,
+ payee,
+ poolMembers,
+ claimPermissions,
+ nominators,
+ ]) => {
+ this.handleLedger(ledger);
+ this.handleAccount(account, locks);
+ this.handlePayee(payee);
+
+ await this.handlePoolMembership(
+ pApi,
+ poolMembers,
+ claimPermissions
+ );
+ this.handleNominations(nominators);
+
+ // Send updated account state back to UI.
+ const accountBalance = {
+ address: this.#address,
+ ledger: this.ledger,
+ balances: this.balance,
+ payee: this.payee,
+ poolMembership: this.poolMembership,
+ nominations: this.nominations,
+ };
+
+ document.dispatchEvent(
+ new CustomEvent('new-account-balance', { detail: accountBalance })
+ );
+ }
+ );
+
+ this.#sub = sub;
+ }
+ } catch (e) {
+ // Subscription failed.
+ }
+ };
+
+ // Handle ledger result.
+ handleLedger = (ledger: AnyApi): void => {
+ // If ledger is null, remove from class.
+ if (!ledger) {
+ this.ledger = undefined;
+ } else {
+ const { stash, total, active, unlocking } = ledger;
+
+ // Send stash address to UI as event if not presently imported.
+ if (!BalancesController.accounts.includes(stash.toString())) {
+ document.dispatchEvent(
+ new CustomEvent('new-external-account', {
+ detail: { address: stash.toString() },
+ })
+ );
+ }
+
+ this.ledger = {
+ stash: stash.toString(),
+ active: stringToBn(active.toString()),
+ total: stringToBn(total.toString()),
+ unlocking: unlocking.map(
+ ({ era, value }: { era: number; value: bigint }) => ({
+ era: Number(era),
+ value: stringToBn(value.toString()),
+ })
+ ),
+ };
+ }
+ };
+
+ // Handle account callback.
+ handleAccount = (
+ { data: accountData, nonce }: AnyApi,
+ locksResult: AnyApi
+ ): void => {
+ this.balance = {
+ nonce,
+ balance: {
+ free: stringToBn(accountData.free.toString()),
+ reserved: stringToBn(accountData.reserved.toString()),
+ frozen: stringToBn(accountData.frozen.toString()),
+ },
+ locks: locksResult.map((lock: { id: AnyApi; amount: bigint }) => ({
+ id: lock.id.asText().trim(),
+ amount: stringToBn(lock.amount.toString()),
+ })),
+ };
+ };
+
+ // Handle payee callback.
+ handlePayee = (result: AnyApi): void => {
+ if (result === undefined) {
+ this.payee = undefined;
+ } else {
+ this.payee = {
+ destination: result.type || null,
+ account: result.value || undefined,
+ };
+ }
+ };
+
+ // Handle pool membership and claim commission callback.
+ handlePoolMembership = async (
+ pApi: PapiApi,
+ poolMembers: AnyApi,
+ claimPermissionResult: AnyApi
+ ): Promise => {
+ // If pool membership is `null`, remove pool membership data from class data and exit early.
+ // This skips claim permission data as well as user would not have claim permissions if they are
+ // not in a pool.
+ if (!poolMembers) {
+ this.poolMembership = undefined;
+ return;
+ }
+
+ const unlocking = poolMembers?.unbonding_eras.map(([e, v]: AnyApi) => ({
+ era: e,
+ value: new BigNumber((v as bigint).toString()),
+ }));
+
+ const apiResult = await pApi.apis.NominationPoolsApi.points_to_balance(
+ poolMembers.pool_id,
+ poolMembers.points
+ );
+ const balance = new BigNumber(apiResult?.toString() || 0);
+ const claimPermission = claimPermissionResult?.type || 'Permissioned';
+
+ this.poolMembership = {
+ address: this.#address,
+ poolId: poolMembers.pool_id,
+ points: poolMembers.points,
+ balance,
+ lastRecordedRewardCounter: poolMembers.last_recorded_reward_counter,
+ unbondingEras: unlocking, // NOTE: This is a duplicate of `unlocking`.
+ claimPermission,
+ unlocking,
+ };
+ };
+
+ // Handle nominations callback.
+ handleNominations = (nominators: AnyApi): void => {
+ this.nominations = !nominators
+ ? defaultNominations
+ : {
+ targets: nominators.targets,
+ submittedIn: nominators.submitted_in,
+ };
+ };
+
+ // Unsubscribe from class subscription.
+ unsubscribe = (): void => {
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
+ }
+ };
+}
From 9af050a95d9696420a2b25f5749932dc508ac473 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 14:19:00 +0700
Subject: [PATCH 33/84] fetch one `BondedPool`
---
.../src/contexts/Pools/BondedPools/index.tsx | 9 +--
.../src/model/Entries/BondedPools/index.tsx | 78 +++++++++++--------
2 files changed, 48 insertions(+), 39 deletions(-)
diff --git a/packages/app/src/contexts/Pools/BondedPools/index.tsx b/packages/app/src/contexts/Pools/BondedPools/index.tsx
index 89ab2984d..2c57d526c 100644
--- a/packages/app/src/contexts/Pools/BondedPools/index.tsx
+++ b/packages/app/src/contexts/Pools/BondedPools/index.tsx
@@ -135,13 +135,8 @@ export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
// Queries a bonded pool and injects ID and addresses to a result.
const queryBondedPool = async (id: number) => {
- if (!api) {
- return null;
- }
-
- const bondedPool: AnyApi = (
- await api.query.nominationPools.bondedPools(id)
- ).toHuman();
+ const { pApi } = ApiController.get(network);
+ const bondedPool = new BondedPools(pApi).fetchOne(id);
if (!bondedPool) {
return null;
diff --git a/packages/app/src/model/Entries/BondedPools/index.tsx b/packages/app/src/model/Entries/BondedPools/index.tsx
index a6ae9466b..9fa767917 100644
--- a/packages/app/src/model/Entries/BondedPools/index.tsx
+++ b/packages/app/src/model/Entries/BondedPools/index.tsx
@@ -21,46 +21,60 @@ export class BondedPools {
return this;
}
- format() {
+ async fetchOne(id: number) {
+ const result =
+ await this.#pApi.query.NominationPools.BondedPools.getValue(id);
+
+ if (!result) {
+ return null;
+ }
+ return this.formatPool(result);
+ }
+
+ format(entry?: AnyApi) {
return Object.fromEntries(
- this.bondedPools.map(
+ (entry ? [entry] : this.bondedPools).map(
({ keyArgs, value }: { keyArgs: [number]; value: AnyApi }) => {
const id = keyArgs[0];
+ const pool = this.formatPool(value);
+ return [id, pool];
+ }
+ )
+ );
+ }
- const maybeCommissionCurrent = value.commission.current;
- const commissionCurrent = !maybeCommissionCurrent
- ? null
- : [
- perbillToPercent(maybeCommissionCurrent[0]).toString(),
- maybeCommissionCurrent[1],
- ];
+ formatPool(value: AnyApi) {
+ const maybeCommissionCurrent = value.commission.current;
+ const commissionCurrent = !maybeCommissionCurrent
+ ? null
+ : [
+ perbillToPercent(maybeCommissionCurrent[0]).toString(),
+ maybeCommissionCurrent[1],
+ ];
- const commissionMax = value.commission.max;
- const commissionMaxPercent = !commissionMax
- ? null
- : perbillToPercent(new BigNumber(value.commission.max));
+ const commissionMax = value.commission.max;
+ const commissionMaxPercent = !commissionMax
+ ? null
+ : perbillToPercent(new BigNumber(value.commission.max));
- const commissionChangeRate = value.commission.change_rate;
+ const commissionChangeRate = value.commission.change_rate;
- const commission = {
- current: commissionCurrent,
- claimPermission: value.commission.claim_permission?.type || null,
- max: commissionMaxPercent,
- changeRate: commissionChangeRate || null,
- throttleFrom: value.commission.throttle_from || null,
- };
+ const commission = {
+ current: commissionCurrent,
+ claimPermission: value.commission.claim_permission?.type || null,
+ max: commissionMaxPercent,
+ changeRate: commissionChangeRate || null,
+ throttleFrom: value.commission.throttle_from || null,
+ };
- const pool = {
- commission,
- points: value.points.toString(),
- memberCounter: value.member_counter.toString(),
- roles: value.roles,
- state: value.state.type,
- };
+ const pool = {
+ commission,
+ points: value.points.toString(),
+ memberCounter: value.member_counter.toString(),
+ roles: value.roles,
+ state: value.state.type,
+ };
- return [id, pool];
- }
- )
- );
+ return pool;
}
}
From 8a85908f338ce7e0f4cbac6087e18fc26ce78c01 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 14:28:40 +0700
Subject: [PATCH 34/84] stop fetching pool member entries
---
.../src/canvas/CreatePool/Summary/index.tsx | 8 ---
.../src/canvas/JoinPool/Overview/JoinForm.tsx | 8 ---
.../app/src/canvas/PoolMembers/Members.tsx | 17 +-----
.../contexts/Pools/PoolMembers/defaults.ts | 3 --
.../src/contexts/Pools/PoolMembers/index.tsx | 53 +------------------
.../src/contexts/Pools/PoolMembers/types.ts | 3 --
packages/app/src/library/Headers/Sync.tsx | 9 +---
.../src/pages/Pools/Home/PoolStats/index.tsx | 18 ++++---
8 files changed, 15 insertions(+), 104 deletions(-)
diff --git a/packages/app/src/canvas/CreatePool/Summary/index.tsx b/packages/app/src/canvas/CreatePool/Summary/index.tsx
index d02c4c649..ff55af33c 100644
--- a/packages/app/src/canvas/CreatePool/Summary/index.tsx
+++ b/packages/app/src/canvas/CreatePool/Summary/index.tsx
@@ -7,7 +7,6 @@ import { unitToPlanck } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import { useTranslation } from 'react-i18next';
import { useBondedPools } from 'contexts/Pools/BondedPools';
-import { usePoolMembers } from 'contexts/Pools/PoolMembers';
import { useSetup } from 'contexts/Setup';
import { Warning } from 'library/Form/Warning';
import { useBatchCall } from 'hooks/useBatchCall';
@@ -37,7 +36,6 @@ export const Summary = ({ section }: SetupStepProps) => {
const { accountHasSigner } = useImportedAccounts();
const { getPoolSetup, removeSetupProgress } = useSetup();
const { activeAccount, activeProxy } = useActiveAccounts();
- const { queryPoolMember, addToPoolMembers } = usePoolMembers();
const { queryBondedPool, addToBondedPools } = useBondedPools();
const poolId = lastPoolId.plus(1);
@@ -82,12 +80,6 @@ export const Summary = ({ section }: SetupStepProps) => {
const pool = await queryBondedPool(poolId.toNumber());
addToBondedPools(pool);
- // Query and add account to poolMembers list.
- const member = await queryPoolMember(activeAccount);
- if (member) {
- addToPoolMembers(member);
- }
-
// Reset setup progress.
removeSetupProgress('pool', activeAccount);
},
diff --git a/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx b/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx
index e9c2181d4..31024e3fd 100644
--- a/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx
+++ b/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx
@@ -17,7 +17,6 @@ import { useBatchCall } from 'hooks/useBatchCall';
import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { useOverlay } from 'kits/Overlay/Provider';
import { useSetup } from 'contexts/Setup';
-import { usePoolMembers } from 'contexts/Pools/PoolMembers';
import { defaultPoolProgress } from 'contexts/Setup/defaults';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
import { SubmitTx } from 'library/SubmitTx';
@@ -42,7 +41,6 @@ export const JoinForm = ({ bondedPool }: OverviewSectionProps) => {
const { getSignerWarnings } = useSignerWarnings();
const { getTransferOptions } = useTransferOptions();
const largestTxFee = useBondGreatestFee({ bondFor: 'pool' });
- const { queryPoolMember, addToPoolMembers } = usePoolMembers();
const {
pool: { totalPossibleBond },
@@ -112,12 +110,6 @@ export const JoinForm = ({ bondedPool }: OverviewSectionProps) => {
}
},
callbackInBlock: async () => {
- // Query and add account to poolMembers list
- const member = await queryPoolMember(activeAccount);
- if (member) {
- addToPoolMembers(member);
- }
-
// Reset local storage setup progress
setActiveAccountSetup('pool', defaultPoolProgress);
},
diff --git a/packages/app/src/canvas/PoolMembers/Members.tsx b/packages/app/src/canvas/PoolMembers/Members.tsx
index 4eebd8b07..c207ae15c 100644
--- a/packages/app/src/canvas/PoolMembers/Members.tsx
+++ b/packages/app/src/canvas/PoolMembers/Members.tsx
@@ -4,20 +4,15 @@
import { faBars } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useTranslation } from 'react-i18next';
-import { usePlugins } from 'contexts/Plugins';
import { useActivePool } from 'contexts/Pools/ActivePool';
-import { usePoolMembers } from 'contexts/Pools/PoolMembers';
import { useTheme } from 'contexts/Themes';
import { CardWrapper } from 'library/Card/Wrappers';
import { useNetwork } from 'contexts/Network';
-import { MembersList as DefaultMemberList } from './Lists/Default';
import { MembersList as FetchPageMemberList } from './Lists/FetchPage';
export const Members = () => {
const { t } = useTranslation('pages');
const { mode } = useTheme();
- const { pluginEnabled } = usePlugins();
- const { getMembersOfPoolFromNode } = usePoolMembers();
const { activePool, isOwner, isBouncer } = useActivePool();
const { colors } = useNetwork().networkData;
@@ -78,17 +73,7 @@ export const Members = () => {
)}
- {pluginEnabled('subscan') ? (
-
- ) : (
-
- )}
+
>
);
diff --git a/packages/app/src/contexts/Pools/PoolMembers/defaults.ts b/packages/app/src/contexts/Pools/PoolMembers/defaults.ts
index 5574bccb0..d27bff742 100644
--- a/packages/app/src/contexts/Pools/PoolMembers/defaults.ts
+++ b/packages/app/src/contexts/Pools/PoolMembers/defaults.ts
@@ -7,12 +7,9 @@ import type { PoolMemberContext } from './types';
export const defaultPoolMembers: PoolMemberContext = {
fetchPoolMembersMetaBatch: (k, v, r) => {},
queryPoolMember: (who) => new Promise((resolve) => resolve(null)),
- getMembersOfPoolFromNode: (poolId) => null,
- addToPoolMembers: (m) => {},
removePoolMember: (w) => {},
poolMembersApi: [],
setPoolMembersApi: (p) => {},
- poolMembersNode: [],
meta: {},
fetchedPoolMembersApi: 'unsynced',
setFetchedPoolMembersApi: (s) => {},
diff --git a/packages/app/src/contexts/Pools/PoolMembers/index.tsx b/packages/app/src/contexts/Pools/PoolMembers/index.tsx
index 8d2f28f36..80f7b9e2b 100644
--- a/packages/app/src/contexts/Pools/PoolMembers/index.tsx
+++ b/packages/app/src/contexts/Pools/PoolMembers/index.tsx
@@ -25,9 +25,6 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
const { pluginEnabled } = usePlugins();
const { activeAccount } = useActiveAccounts();
- // Store pool members from node.
- const [poolMembersNode, setPoolMembersNode] = useState([]);
-
// Store pool members from api.
const [poolMembersApi, setPoolMembersApi] = useState([]);
@@ -49,7 +46,6 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
// Clear existing state for network refresh
useEffectIgnoreInitial(() => {
- setPoolMembersNode([]);
setPoolMembersApi([]);
unsubscribeAndResetMeta();
}, [network]);
@@ -62,12 +58,7 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
// Initial setup for fetching members if Subscan is not enabled. Ensure poolMembers are reset if
// subscan is disabled.
useEffectIgnoreInitial(() => {
- if (!pluginEnabled('subscan')) {
- if (isReady) {
- fetchPoolMembersNode();
- }
- } else {
- setPoolMembersNode([]);
+ if (pluginEnabled('subscan')) {
setPoolMembersApi([]);
}
return () => {
@@ -77,7 +68,6 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
const unsubscribe = () => {
unsubscribeAndResetMeta();
- setPoolMembersNode([]);
setPoolMembersApi([]);
};
@@ -88,26 +78,6 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
setStateWithRef({}, setPoolMembersMetaBatch, poolMembersMetaBatchesRef);
};
- // Fetch all pool members entries from node.
- const fetchPoolMembersNode = async () => {
- if (!api) {
- return;
- }
- const result = await api.query.nominationPools.poolMembers.entries();
- const newMembers = result.map(([keys, val]: AnyApi) => {
- const who = keys.toHuman()[0];
- const { poolId } = val.toHuman();
- return {
- who,
- poolId,
- };
- });
- setPoolMembersNode(newMembers);
- };
-
- const getMembersOfPoolFromNode = (poolId: number) =>
- poolMembersNode.filter((p) => String(p.poolId) === String(poolId)) ?? null;
-
// queries a pool member and formats to `PoolMember`.
const queryPoolMember = async (who: MaybeAddress) => {
if (!api) {
@@ -221,26 +191,10 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
);
};
- // Removes a member from the member list and updates state.
+ // Removes a member from the member list and updates state. Requires subscan to be enabled.
const removePoolMember = (who: MaybeAddress) => {
- // If Subscan is enabled, update API state, otherwise, update node state.
if (pluginEnabled('subscan')) {
setPoolMembersApi(poolMembersApi.filter((p) => p.who !== who) ?? []);
- } else {
- setPoolMembersNode(poolMembersNode.filter((p) => p.who !== who) ?? []);
- }
- };
-
- // Adds a record to poolMembers.
- // Currently only used when an account joins or creates a pool.
- const addToPoolMembers = (member: { who: string; poolId: number }) => {
- if (!member || pluginEnabled('subscan')) {
- return;
- }
-
- const exists = poolMembersNode.find((m) => m.who === member.who);
- if (!exists) {
- setPoolMembersNode(poolMembersNode.concat(member));
}
};
@@ -260,10 +214,7 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
value={{
fetchPoolMembersMetaBatch,
queryPoolMember,
- getMembersOfPoolFromNode,
- addToPoolMembers,
removePoolMember,
- poolMembersNode,
poolMembersApi,
setPoolMembersApi,
fetchedPoolMembersApi: fetchedPoolMembersApi.current,
diff --git a/packages/app/src/contexts/Pools/PoolMembers/types.ts b/packages/app/src/contexts/Pools/PoolMembers/types.ts
index e7b6dd30d..bed2f11b4 100644
--- a/packages/app/src/contexts/Pools/PoolMembers/types.ts
+++ b/packages/app/src/contexts/Pools/PoolMembers/types.ts
@@ -7,10 +7,7 @@ import type { AnyMetaBatch, MaybeAddress } from 'types';
export interface PoolMemberContext {
fetchPoolMembersMetaBatch: (k: string, v: AnyMetaBatch[], r: boolean) => void;
queryPoolMember: (who: MaybeAddress) => Promise;
- getMembersOfPoolFromNode: (poolId: number) => PoolMember[] | null;
- addToPoolMembers: (member: PoolMember) => void;
removePoolMember: (w: MaybeAddress) => void;
- poolMembersNode: PoolMember[];
meta: AnyMetaBatch;
poolMembersApi: PoolMember[];
setPoolMembersApi: (p: PoolMember[]) => void;
diff --git a/packages/app/src/library/Headers/Sync.tsx b/packages/app/src/library/Headers/Sync.tsx
index 8c9349688..e9d954c4e 100644
--- a/packages/app/src/library/Headers/Sync.tsx
+++ b/packages/app/src/library/Headers/Sync.tsx
@@ -3,9 +3,7 @@
import { pageFromUri } from '@w3ux/utils';
import { useLocation } from 'react-router-dom';
-import { usePlugins } from 'contexts/Plugins';
import { useBondedPools } from 'contexts/Pools/BondedPools';
-import { usePoolMembers } from 'contexts/Pools/PoolMembers';
import { useValidators } from 'contexts/Validators/ValidatorEntries';
import { usePayouts } from 'contexts/Payouts';
import { Spinner } from './Spinner';
@@ -17,10 +15,8 @@ export const Sync = () => {
const { pathname } = useLocation();
const { pendingNonces } = useTxMeta();
const { payoutsSynced } = usePayouts();
- const { pluginEnabled } = usePlugins();
const { validators } = useValidators();
const { bondedPools } = useBondedPools();
- const { poolMembersNode } = usePoolMembers();
// Keep syncing if on nominate page and still fetching payouts.
const onNominateSyncing = () => {
@@ -37,10 +33,7 @@ export const Sync = () => {
// member sync if Subscan is enabled.
const onPoolsSyncing = () => {
if (pageFromUri(pathname, 'overview') === 'pools') {
- if (
- !bondedPools.length ||
- (!poolMembersNode.length && !pluginEnabled('subscan'))
- ) {
+ if (!bondedPools.length) {
return true;
}
}
diff --git a/packages/app/src/pages/Pools/Home/PoolStats/index.tsx b/packages/app/src/pages/Pools/Home/PoolStats/index.tsx
index 3f0bf279f..6215f6b9a 100644
--- a/packages/app/src/pages/Pools/Home/PoolStats/index.tsx
+++ b/packages/app/src/pages/Pools/Home/PoolStats/index.tsx
@@ -14,6 +14,7 @@ import type { PoolStatLabel } from 'library/Announcements/types';
import { useOverlay } from 'kits/Overlay/Provider';
import { Wrapper } from 'library/Announcements/Wrappers';
import { planckToUnitBn } from 'library/Utils';
+import { usePlugins } from 'contexts/Plugins';
export const PoolStats = () => {
const { t } = useTranslation('pages');
@@ -21,6 +22,7 @@ export const PoolStats = () => {
const {
networkData: { units, unit },
} = useNetwork();
+ const { pluginEnabled } = usePlugins();
const { activePool } = useActivePool();
const { getCurrentCommission } = usePoolCommission();
@@ -67,13 +69,15 @@ export const PoolStats = () => {
{
label: t('pools.poolMembers'),
value: `${memberCounter}`,
- button: {
- text: t('pools.browseMembers'),
- onClick: () => {
- openCanvas({ key: 'PoolMembers', size: 'xl' });
- },
- disabled: memberCounter === '0',
- },
+ button: pluginEnabled('subscan')
+ ? {
+ text: t('pools.browseMembers'),
+ onClick: () => {
+ openCanvas({ key: 'PoolMembers', size: 'xl' });
+ },
+ disabled: memberCounter === '0',
+ }
+ : undefined,
},
{
label: t('pools.totalBonded'),
From b4805db66ec845a6d3bfe7014777bd208171dbcc Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 14:42:14 +0700
Subject: [PATCH 35/84] discontinue `queryPoolMember`
---
.../contexts/Pools/PoolMembers/defaults.ts | 1 -
.../src/contexts/Pools/PoolMembers/index.tsx | 21 -------------------
.../src/contexts/Pools/PoolMembers/types.ts | 1 -
3 files changed, 23 deletions(-)
diff --git a/packages/app/src/contexts/Pools/PoolMembers/defaults.ts b/packages/app/src/contexts/Pools/PoolMembers/defaults.ts
index d27bff742..39a1d3a0f 100644
--- a/packages/app/src/contexts/Pools/PoolMembers/defaults.ts
+++ b/packages/app/src/contexts/Pools/PoolMembers/defaults.ts
@@ -6,7 +6,6 @@ import type { PoolMemberContext } from './types';
export const defaultPoolMembers: PoolMemberContext = {
fetchPoolMembersMetaBatch: (k, v, r) => {},
- queryPoolMember: (who) => new Promise((resolve) => resolve(null)),
removePoolMember: (w) => {},
poolMembersApi: [],
setPoolMembersApi: (p) => {},
diff --git a/packages/app/src/contexts/Pools/PoolMembers/index.tsx b/packages/app/src/contexts/Pools/PoolMembers/index.tsx
index 80f7b9e2b..02cf7dcdd 100644
--- a/packages/app/src/contexts/Pools/PoolMembers/index.tsx
+++ b/packages/app/src/contexts/Pools/PoolMembers/index.tsx
@@ -78,26 +78,6 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
setStateWithRef({}, setPoolMembersMetaBatch, poolMembersMetaBatchesRef);
};
- // queries a pool member and formats to `PoolMember`.
- const queryPoolMember = async (who: MaybeAddress) => {
- if (!api) {
- return null;
- }
-
- const poolMember: AnyApi = (
- await api.query.nominationPools.poolMembers(who)
- ).toHuman();
-
- if (!poolMember) {
- return null;
- }
-
- return {
- who,
- poolId: poolMember.poolId,
- } as PoolMember;
- };
-
/*
Fetches a new batch of pool member metadata.
structure:
@@ -213,7 +193,6 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
void;
- queryPoolMember: (who: MaybeAddress) => Promise;
removePoolMember: (w: MaybeAddress) => void;
meta: AnyMetaBatch;
poolMembersApi: PoolMember[];
From 2dbca3428a289c21069c34c54f85f45f38766b00 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 14:53:55 +0700
Subject: [PATCH 36/84] fix
---
packages/app/src/model/Subscribe/AccountBalances/index.ts | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/packages/app/src/model/Subscribe/AccountBalances/index.ts b/packages/app/src/model/Subscribe/AccountBalances/index.ts
index d9ecc7684..612124f6a 100644
--- a/packages/app/src/model/Subscribe/AccountBalances/index.ts
+++ b/packages/app/src/model/Subscribe/AccountBalances/index.ts
@@ -204,9 +204,10 @@ export class AccountBalances implements Unsubscribable {
this.poolMembership = {
address: this.#address,
poolId: poolMembers.pool_id,
- points: poolMembers.points,
+ points: poolMembers.points.toString(),
balance,
- lastRecordedRewardCounter: poolMembers.last_recorded_reward_counter,
+ lastRecordedRewardCounter:
+ poolMembers.last_recorded_reward_counter.toString(),
unbondingEras: unlocking, // NOTE: This is a duplicate of `unlocking`.
claimPermission,
unlocking,
From 2af98fbda9eca0bb31235bb6760d5b874f178b0c Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 14:54:09 +0700
Subject: [PATCH 37/84] remove discontinued list
---
.../src/canvas/PoolMembers/Lists/Default.tsx | 104 ------------------
.../app/src/canvas/PoolMembers/Lists/types.ts | 6 -
2 files changed, 110 deletions(-)
delete mode 100644 packages/app/src/canvas/PoolMembers/Lists/Default.tsx
diff --git a/packages/app/src/canvas/PoolMembers/Lists/Default.tsx b/packages/app/src/canvas/PoolMembers/Lists/Default.tsx
deleted file mode 100644
index 32e1937c6..000000000
--- a/packages/app/src/canvas/PoolMembers/Lists/Default.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
-// SPDX-License-Identifier: GPL-3.0-only
-
-import { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { poolMembersPerPage } from 'library/List/defaults';
-import { useApi } from 'contexts/Api';
-import { usePoolMembers } from 'contexts/Pools/PoolMembers';
-import { List, ListStatusHeader, Wrapper as ListWrapper } from 'library/List';
-import { Pagination } from 'library/List/Pagination';
-import { ListProvider } from 'library/List/context';
-import type { Sync } from '@w3ux/types';
-import { Member } from './Member';
-import type { DefaultMembersListProps } from './types';
-import type { PoolMember } from 'contexts/Pools/PoolMembers/types';
-import { MotionContainer } from 'library/List/MotionContainer';
-
-export const MembersListInner = ({
- pagination,
- batchKey,
- members: initialMembers,
-}: DefaultMembersListProps) => {
- const { t } = useTranslation('pages');
- const { isReady, activeEra } = useApi();
- const { fetchPoolMembersMetaBatch } = usePoolMembers();
-
- // current page
- const [page, setPage] = useState(1);
-
- // default list of validators
- const [membersDefault, setMembersDefault] =
- useState(initialMembers);
-
- // manipulated list (ordering, filtering) of payouts
- const [members, setMembers] = useState(initialMembers);
-
- // is this the initial fetch
- const [fetched, setFetched] = useState('unsynced');
-
- // pagination
- const totalPages = Math.ceil(members.length / poolMembersPerPage);
- const pageEnd = page * poolMembersPerPage - 1;
- const pageStart = pageEnd - (poolMembersPerPage - 1);
-
- // get throttled subset or entire list
- const listMembers = members.slice(pageStart).slice(0, poolMembersPerPage);
-
- // handle validator list bootstrapping
- const setupMembersList = () => {
- setMembersDefault(initialMembers);
- setMembers(initialMembers);
- fetchPoolMembersMetaBatch(batchKey, initialMembers, false);
- setFetched('synced');
- };
-
- // Refetch list when list changes.
- useEffect(() => {
- if (initialMembers !== membersDefault) {
- setFetched('unsynced');
- }
- }, [initialMembers]);
-
- // Configure list when network is ready to fetch.
- useEffect(() => {
- if (isReady && !activeEra.index.isZero() && fetched === 'unsynced') {
- setupMembersList();
- }
- }, [isReady, fetched, activeEra.index]);
-
- return !members.length ? null : (
-
-
- {listMembers.length > 0 && pagination && (
-
- )}
- {fetched !== 'synced' ? (
-
- {t('pools.fetchingMemberList')}...
-
- ) : (
-
- {listMembers.map((member: PoolMember, index: number) => (
-
- ))}
-
- )}
-
-
- );
-};
-
-export const MembersList = (props: DefaultMembersListProps) => {
- const { selectToggleable } = props;
- return (
-
-
-
- );
-};
diff --git a/packages/app/src/canvas/PoolMembers/Lists/types.ts b/packages/app/src/canvas/PoolMembers/Lists/types.ts
index 0e66b3a75..9103cd8c3 100644
--- a/packages/app/src/canvas/PoolMembers/Lists/types.ts
+++ b/packages/app/src/canvas/PoolMembers/Lists/types.ts
@@ -1,18 +1,12 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { AnyJson } from '@w3ux/types';
-
export interface MembersListProps {
pagination: boolean;
batchKey: string;
selectToggleable?: boolean;
}
-export type DefaultMembersListProps = MembersListProps & {
- members: AnyJson;
-};
-
export type FetchpageMembersListProps = MembersListProps & {
memberCount: string;
};
From 0b83be34b0ccb4a3a0ec68c8097eb047ecaf5b51 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 16:07:34 +0700
Subject: [PATCH 38/84] migrate Pool multi queries to classes
---
.../src/contexts/Pools/BondedPools/index.tsx | 52 ++++++++-----------
.../src/model/Query/NominatorsMulti/index.ts | 39 ++++++++++++++
.../model/Query/PoolMetadataMulti/index.ts | 28 ++++++++++
3 files changed, 89 insertions(+), 30 deletions(-)
create mode 100644 packages/app/src/model/Query/NominatorsMulti/index.ts
create mode 100644 packages/app/src/model/Query/PoolMetadataMulti/index.ts
diff --git a/packages/app/src/contexts/Pools/BondedPools/index.tsx b/packages/app/src/contexts/Pools/BondedPools/index.tsx
index 2c57d526c..12d2b283f 100644
--- a/packages/app/src/contexts/Pools/BondedPools/index.tsx
+++ b/packages/app/src/contexts/Pools/BondedPools/index.tsx
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only
import { u8aUnwrapBytes, u8aToString } from '@polkadot/util';
-import { rmCommas, setStateWithRef, shuffle } from '@w3ux/utils';
+import { setStateWithRef, shuffle } from '@w3ux/utils';
import type { ReactNode } from 'react';
import { createContext, useContext, useRef, useState } from 'react';
import type {
@@ -25,6 +25,8 @@ import { useCreatePoolAccounts } from 'hooks/useCreatePoolAccounts';
import { SyncController } from 'controllers/Sync';
import { BondedPools } from 'model/Entries/BondedPools';
import { ApiController } from 'controllers/Api';
+import { NominatorsMulti } from 'model/Query/NominatorsMulti';
+import { PoolMetadataMulti } from 'model/Query/PoolMetadataMulti';
export const BondedPoolsContext = createContext(
defaultBondedPoolsContext
@@ -35,7 +37,6 @@ export const useBondedPools = () => useContext(BondedPoolsContext);
export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
const {
- api,
isReady,
activeEra,
poolsConfig: { lastPoolId },
@@ -67,32 +68,30 @@ export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
const fetchBondedPools = async () => {
const { pApi } = ApiController.get(network);
- if (!api || !pApi || bondedPoolsSynced.current !== 'unsynced') {
+ if (!pApi || bondedPoolsSynced.current !== 'unsynced') {
return;
}
bondedPoolsSynced.current = 'syncing';
- const ids: number[] = [];
-
// Get and format bonded pool entries.
+ const ids: number[] = [];
+ const idsMulti: [number][] = [];
const bondedPoolsEntries = (await new BondedPools(pApi).fetch()).format();
- let exposures = Object.entries(bondedPoolsEntries).map(
- ([id, pool]: AnyApi) => {
+ const exposures = shuffle(
+ Object.entries(bondedPoolsEntries).map(([id, pool]: AnyApi) => {
ids.push(id);
+ idsMulti.push([id]);
return getPoolWithAddresses(id, pool);
- }
+ })
);
- exposures = shuffle(exposures);
setStateWithRef(exposures, setBondedPools, bondedPoolsRef);
// Fetch pools metadata.
- const metadataMulti = await api.query.nominationPools.metadata.multi(ids);
+ const metadataQuery = await new PoolMetadataMulti(pApi, idsMulti).fetch();
setPoolsMetadata(
- Object.fromEntries(
- metadataMulti.map((m, i) => [ids[i], String(m.toHuman())])
- )
+ Object.fromEntries(metadataQuery.map((m, i) => [ids[i], m]))
);
bondedPoolsSynced.current = 'synced';
@@ -101,35 +100,28 @@ export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
// Fetches pool nominations and updates state.
const fetchPoolsNominations = async () => {
- if (!api) {
+ const { pApi } = ApiController.get(network);
+ if (!pApi) {
return;
}
const ids: number[] = [];
- const nominationsMulti = await api.query.staking.nominators.multi(
- bondedPools.map(({ addresses, id }) => {
- ids.push(id);
- return addresses.stash;
- })
- );
+ const stashes: [string][] = bondedPools.map(({ addresses, id }) => {
+ ids.push(id);
+ return [addresses.stash];
+ });
+ const nominationsMulti = await new NominatorsMulti(pApi, stashes).fetch();
setPoolsNominations(formatPoolsNominations(nominationsMulti, ids));
};
// Format raw pool nominations data.
const formatPoolsNominations = (raw: AnyJson, ids: number[]) =>
Object.fromEntries(
- raw.map((n: AnyJson, i: number) => {
- const human = n.toHuman() as PoolNominations;
- if (!human) {
+ raw.map((nominator: AnyJson, i: number) => {
+ if (!nominator) {
return [ids[i], null];
}
- return [
- ids[i],
- {
- ...human,
- submittedIn: rmCommas(human.submittedIn),
- },
- ];
+ return [ids[i], { ...nominator }];
})
);
diff --git a/packages/app/src/model/Query/NominatorsMulti/index.ts b/packages/app/src/model/Query/NominatorsMulti/index.ts
new file mode 100644
index 000000000..c9279c596
--- /dev/null
+++ b/packages/app/src/model/Query/NominatorsMulti/index.ts
@@ -0,0 +1,39 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class NominatorsMulti {
+ #pApi: PapiApi;
+
+ #addresses: [string][];
+
+ constructor(pApi: PapiApi, addresses: [string][]) {
+ this.#pApi = pApi;
+ this.#addresses = addresses;
+ }
+
+ async fetch() {
+ let result;
+ try {
+ result = await this.#pApi.query.Staking.Nominators.getValues(
+ this.#addresses
+ );
+
+ return result.map((nominator) => {
+ if (!nominator) {
+ return undefined;
+ }
+ return {
+ submittedIn: String(nominator.submitted_in),
+ suppressed: nominator.suppressed,
+ targets: nominator.targets,
+ };
+ });
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return null;
+ }
+}
diff --git a/packages/app/src/model/Query/PoolMetadataMulti/index.ts b/packages/app/src/model/Query/PoolMetadataMulti/index.ts
new file mode 100644
index 000000000..e28220f5b
--- /dev/null
+++ b/packages/app/src/model/Query/PoolMetadataMulti/index.ts
@@ -0,0 +1,28 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class PoolMetadataMulti {
+ #pApi: PapiApi;
+
+ #ids: [number][];
+
+ constructor(pApi: PapiApi, ids: [number][]) {
+ this.#pApi = pApi;
+ this.#ids = ids;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.NominationPools.Metadata.getValues(
+ this.#ids
+ );
+ return result.map((metadata) => metadata.asText());
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return [];
+ }
+}
From 61c0fe6fc45db7de5e4e77d971537f492b195053 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 16:28:38 +0700
Subject: [PATCH 39/84] account proxies to `AccountProxies` subscription class
---
packages/app/src/contexts/Proxies/index.tsx | 109 ++++++++----------
.../src/controllers/Subscriptions/types.ts | 2 +
.../model/Subscribe/AccountProxies/index.ts | 55 +++++++++
.../model/Subscribe/AccountProxies/types.ts | 19 +++
packages/app/src/types.ts | 2 +
5 files changed, 129 insertions(+), 58 deletions(-)
create mode 100644 packages/app/src/model/Subscribe/AccountProxies/index.ts
create mode 100644 packages/app/src/model/Subscribe/AccountProxies/types.ts
diff --git a/packages/app/src/contexts/Proxies/index.tsx b/packages/app/src/contexts/Proxies/index.tsx
index 1ef1c9b0c..21c5fa3aa 100644
--- a/packages/app/src/contexts/Proxies/index.tsx
+++ b/packages/app/src/contexts/Proxies/index.tsx
@@ -1,14 +1,12 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
import {
addedTo,
ellipsisFn,
localStorageOrDefault,
matchedProperties,
removedFrom,
- rmCommas,
setStateWithRef,
} from '@w3ux/utils';
import BigNumber from 'bignumber.js';
@@ -33,6 +31,10 @@ import type {
ProxyDelegate,
} from './types';
import { defaultNetwork } from 'contexts/Network/defaults';
+import { SubscriptionsController } from 'controllers/Subscriptions';
+import { AccountProxies } from 'model/Subscribe/AccountProxies';
+import { useEventListener } from 'usehooks-ts';
+import { isCustomEvent } from 'controllers/utils';
export const ProxiesContext = createContext(
defaults.defaultProxiesContext
@@ -51,7 +53,6 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
// Store the proxy accounts of each imported account.
const [proxies, setProxies] = useState([]);
const proxiesRef = useRef(proxies);
- const unsubs = useRef>({});
// Store the last network proxies were synced on.
const [lastSyncedNetwork, setLastSyncedNetwork] =
@@ -106,17 +107,11 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
addOrReplaceOtherAccount(importResult.account, importResult.type);
}
} else {
- const unsub = unsubs.current[address];
- if (unsub) {
- unsub();
- }
+ SubscriptionsController.remove(network, `accountProxies-${address}`);
}
});
-
- unsubs.current = Object.fromEntries(
- Object.entries(unsubs.current).filter(([key]) => !removed.includes(key))
- );
};
+
// Sync added accounts.
const handleAddedAccounts = () => {
addedTo(accounts, proxies, ['address'])?.map(({ address }) =>
@@ -147,45 +142,11 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
if (!api) {
return undefined;
}
-
- const unsub = await api.queryMulti(
- [[api.query.proxy.proxies, address]],
- async ([result]) => {
- const data = result.toHuman();
- const newProxies = data[0];
- const reserved = new BigNumber(rmCommas(data[1]));
-
- if (newProxies.length) {
- setStateWithRef(
- [...proxiesRef.current]
- .filter(({ delegator }) => delegator !== address)
- .concat({
- address,
- delegator: address,
- delegates: newProxies.map((d: AnyApi) => ({
- delegate: d.delegate.toString(),
- proxyType: d.proxyType.toString(),
- })),
- reserved,
- }),
- setProxies,
- proxiesRef
- );
- } else {
- // no proxies: remove stale proxies if already in list.
- setStateWithRef(
- [...proxiesRef.current].filter(
- ({ delegator }) => delegator !== address
- ),
- setProxies,
- proxiesRef
- );
- }
- }
+ SubscriptionsController.set(
+ network,
+ `accountProxies-${address}`,
+ new AccountProxies(network, address)
);
-
- unsubs.current[address] = unsub;
- return unsub;
};
// Gets the delegates of the given account.
@@ -215,6 +176,7 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
return [];
}
+ // TODO: Migrate to query class.
const result: AnyApi = (await api.query.proxy.proxies(delegator)).toHuman();
let addDelegatorAsExternal = false;
@@ -246,6 +208,43 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
.find((p) => p.delegator === delegator)
?.delegates.find((d) => d.delegate === delegate) ?? null;
+ // Handle account proxies events.
+ const handleAccountProxies = (e: Event) => {
+ if (isCustomEvent(e)) {
+ const { address: eventAddress, proxies: eventProxies } = e.detail;
+
+ const newProxies = eventProxies[0];
+ const reserved = new BigNumber(eventProxies[1].toString());
+
+ if (newProxies.length) {
+ setStateWithRef(
+ [...proxiesRef.current]
+ .filter(({ delegator }) => delegator !== eventAddress)
+ .concat({
+ address: eventAddress,
+ delegator: eventAddress,
+ delegates: newProxies.map((d: AnyApi) => ({
+ delegate: d.delegate.toString(),
+ proxyType: d.proxy_type.type.toString(),
+ })),
+ reserved,
+ }),
+ setProxies,
+ proxiesRef
+ );
+ } else {
+ // no proxies: remove stale proxies if already in list.
+ setStateWithRef(
+ [...proxiesRef.current].filter(
+ ({ delegator }) => delegator !== eventAddress
+ ),
+ setProxies,
+ proxiesRef
+ );
+ }
+ }
+ };
+
// If active proxy has not yet been set, check local storage `activeProxy` & set it as active
// proxy if it is the delegate of `activeAccount`.
useEffectIgnoreInitial(() => {
@@ -293,20 +292,14 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
}
}, [accounts, isReady]);
- // Reset active proxy state, unsubscribe from subscriptions on network change & unmount.
+ // Reset active proxy state on network change & unmount.
useEffectIgnoreInitial(() => {
setStateWithRef([], setProxies, proxiesRef);
setActiveProxy(null, false);
- unsubAll();
- return () => unsubAll();
}, [network]);
- const unsubAll = () => {
- for (const unsub of Object.values(unsubs.current)) {
- unsub();
- }
- unsubs.current = {};
- };
+ const documentRef = useRef(document);
+ useEventListener('new-account-proxies', handleAccountProxies, documentRef);
return (
=> {
+ try {
+ const { pApi } = ApiController.get(this.#network);
+
+ if (pApi && this.#sub === undefined) {
+ const unsub = pApi.query.Proxy.Proxies.watchValue(
+ this.#address
+ ).subscribe((proxies) => {
+ document.dispatchEvent(
+ new CustomEvent('new-account-proxies', {
+ detail: { address: this.#address, proxies },
+ })
+ );
+ });
+ this.#sub = unsub;
+ }
+ } catch (e) {
+ // Subscription failed.
+ }
+ };
+
+ // Unsubscribe from class subscription.
+ unsubscribe = (): void => {
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
+ }
+ };
+}
diff --git a/packages/app/src/model/Subscribe/AccountProxies/types.ts b/packages/app/src/model/Subscribe/AccountProxies/types.ts
new file mode 100644
index 000000000..3e2f79155
--- /dev/null
+++ b/packages/app/src/model/Subscribe/AccountProxies/types.ts
@@ -0,0 +1,19 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+export type AccountProxy = [
+ {
+ delay: number;
+ delegate: string;
+ proxy_type: {
+ type: string;
+ value: undefined;
+ };
+ }[],
+ bigint,
+];
+
+export interface AccountProxiesEvent {
+ address: string;
+ proxies: AccountProxy;
+}
diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts
index 1651a9343..22ae59ee6 100644
--- a/packages/app/src/types.ts
+++ b/packages/app/src/types.ts
@@ -23,6 +23,7 @@ import type { BlockNumberEventDetail } from 'model/Subscribe/BlockNumber/types';
import type { BondedAccount } from 'contexts/Bonded/types';
import type { FastUnstakeConfigResult } from 'model/Subscribe/FastUnstakeConfig/types';
import type { FastUnstakeQueueResult } from 'contexts/FastUnstake/types';
+import type { AccountProxiesEvent } from 'model/Subscribe/AccountProxies/types';
declare global {
interface Window {
@@ -47,6 +48,7 @@ declare global {
'new-active-pool': CustomEvent;
'new-fast-unstake-config': CustomEvent;
'new-fast-unstake-deposit': CustomEvent;
+ 'new-account-proxies': CustomEvent;
'new-bonded-account': CustomEvent;
'new-sync-status': CustomEvent;
'new-external-account': CustomEvent<{ address: string }>;
From 9f1d0a1cc77a7be3e8054fe6a54f58cd4823c780 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 16:35:49 +0700
Subject: [PATCH 40/84] migrate proxy query to `ProxiesQuery`
---
packages/app/src/contexts/Proxies/index.tsx | 16 +++++------
.../app/src/model/Query/ProxiesQuery/index.ts | 28 +++++++++++++++++++
2 files changed, 36 insertions(+), 8 deletions(-)
create mode 100644 packages/app/src/model/Query/ProxiesQuery/index.ts
diff --git a/packages/app/src/contexts/Proxies/index.tsx b/packages/app/src/contexts/Proxies/index.tsx
index 21c5fa3aa..865955765 100644
--- a/packages/app/src/contexts/Proxies/index.tsx
+++ b/packages/app/src/contexts/Proxies/index.tsx
@@ -35,6 +35,8 @@ import { SubscriptionsController } from 'controllers/Subscriptions';
import { AccountProxies } from 'model/Subscribe/AccountProxies';
import { useEventListener } from 'usehooks-ts';
import { isCustomEvent } from 'controllers/utils';
+import { ProxiesQuery } from 'model/Query/ProxiesQuery';
+import { ApiController } from 'controllers/Api';
export const ProxiesContext = createContext(
defaults.defaultProxiesContext
@@ -43,8 +45,8 @@ export const ProxiesContext = createContext(
export const useProxies = () => useContext(ProxiesContext);
export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
+ const { isReady } = useApi();
const { network } = useNetwork();
- const { api, isReady } = useApi();
const { accounts } = useImportedAccounts();
const { addExternalAccount } = useExternalAccounts();
const { addOrReplaceOtherAccount } = useOtherAccounts();
@@ -139,9 +141,6 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
};
const subscribeToProxies = async (address: string) => {
- if (!api) {
- return undefined;
- }
SubscriptionsController.set(
network,
`accountProxies-${address}`,
@@ -172,15 +171,16 @@ export const ProxiesProvider = ({ children }: { children: ReactNode }) => {
// Queries the chain to check if the given delegator & delegate pair is valid proxy. Used when a
// proxy account is being manually declared.
const handleDeclareDelegate = async (delegator: string) => {
- if (!api) {
+ const { pApi } = ApiController.get(network);
+ if (!pApi) {
return [];
}
- // TODO: Migrate to query class.
- const result: AnyApi = (await api.query.proxy.proxies(delegator)).toHuman();
+ const result = await new ProxiesQuery(pApi, delegator).fetch();
+ const proxy = result[0] || [];
let addDelegatorAsExternal = false;
- for (const { delegate: newDelegate } of result[0] || []) {
+ for (const { delegate: newDelegate } of proxy) {
if (
accounts.find(({ address }) => address === newDelegate) &&
!delegates[newDelegate]
diff --git a/packages/app/src/model/Query/ProxiesQuery/index.ts b/packages/app/src/model/Query/ProxiesQuery/index.ts
new file mode 100644
index 000000000..49866d57b
--- /dev/null
+++ b/packages/app/src/model/Query/ProxiesQuery/index.ts
@@ -0,0 +1,28 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ProxiesQuery {
+ #pApi: PapiApi;
+
+ #address: string;
+
+ constructor(pApi: PapiApi, address: string) {
+ this.#pApi = pApi;
+ this.#address = address;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Proxy.Proxies.getValue(
+ this.#address
+ );
+ return result;
+ } catch (e) {
+ // Subscription failed.
+ }
+
+ return undefined;
+ }
+}
From 6cb0cd8799d1c127d7162b72fbdb4ab76df8f2bc Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 16:43:39 +0700
Subject: [PATCH 41/84] add `IdentityOfMulti` class
---
.../src/model/Query/IdentityOfMulti/index.ts | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 packages/app/src/model/Query/IdentityOfMulti/index.ts
diff --git a/packages/app/src/model/Query/IdentityOfMulti/index.ts b/packages/app/src/model/Query/IdentityOfMulti/index.ts
new file mode 100644
index 000000000..d2c8dc5c5
--- /dev/null
+++ b/packages/app/src/model/Query/IdentityOfMulti/index.ts
@@ -0,0 +1,29 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+// TODO: Hook up and test.
+export class IdentityOfMulti {
+ #pApi: PapiApi;
+
+ #addresses: [string][];
+
+ constructor(pApi: PapiApi, addresses: [string][]) {
+ this.#pApi = pApi;
+ this.#addresses = addresses;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Identity.IdentityOf.getValues(
+ this.#addresses
+ );
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return null;
+ }
+}
From c8bc325133f1b710e098b1d9db5d69d922f6a19c Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 17:39:14 +0700
Subject: [PATCH 42/84] use `bestOrFinalized` = `best`
---
.../model/Subscribe/AccountProxies/index.ts | 4 +-
.../src/model/Subscribe/ActiveEra/index.ts | 65 ++++++++++---------
.../src/model/Subscribe/BlockNumber/index.ts | 5 +-
.../app/src/model/Subscribe/Bonded/index.tsx | 4 +-
.../Subscribe/FastUnstakeConfig/index.ts | 6 +-
.../model/Subscribe/FastUnstakeQueue/index.ts | 4 +-
.../model/Subscribe/NetworkMetrics/index.ts | 15 +++--
.../src/model/Subscribe/PoolsConfig/index.ts | 31 ++++++---
.../model/Subscribe/StakingMetrics/index.ts | 20 +++---
9 files changed, 93 insertions(+), 61 deletions(-)
diff --git a/packages/app/src/model/Subscribe/AccountProxies/index.ts b/packages/app/src/model/Subscribe/AccountProxies/index.ts
index 8c07e8f04..b2688cace 100644
--- a/packages/app/src/model/Subscribe/AccountProxies/index.ts
+++ b/packages/app/src/model/Subscribe/AccountProxies/index.ts
@@ -30,8 +30,10 @@ export class AccountProxies implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
const unsub = pApi.query.Proxy.Proxies.watchValue(
- this.#address
+ this.#address,
+ bestOrFinalized
).subscribe((proxies) => {
document.dispatchEvent(
new CustomEvent('new-account-proxies', {
diff --git a/packages/app/src/model/Subscribe/ActiveEra/index.ts b/packages/app/src/model/Subscribe/ActiveEra/index.ts
index 9df6b011a..935fa28f2 100644
--- a/packages/app/src/model/Subscribe/ActiveEra/index.ts
+++ b/packages/app/src/model/Subscribe/ActiveEra/index.ts
@@ -32,43 +32,44 @@ export class ActiveEra implements Unsubscribable {
if (pApi && this.#sub === undefined) {
// Testing the active era subscription.
- const sub = pApi.query.Staking.ActiveEra.watchValue().subscribe(
- (activeEra) => {
- // Store active era.
- this.activeEra = {
- index: new BigNumber(activeEra.index.toString()),
- start: new BigNumber(activeEra.start.toString()),
- };
+ const bestOrFinalized = 'best';
+ const sub = pApi.query.Staking.ActiveEra.watchValue(
+ bestOrFinalized
+ ).subscribe((activeEra) => {
+ // Store active era.
+ this.activeEra = {
+ index: new BigNumber(activeEra.index.toString()),
+ start: new BigNumber(activeEra.start.toString()),
+ };
- // Unsubscribe to staking metrics if it exists.
- const subStakingMetrics = SubscriptionsController.get(
- this.#network,
- 'stakingMetrics'
- );
+ // Unsubscribe to staking metrics if it exists.
+ const subStakingMetrics = SubscriptionsController.get(
+ this.#network,
+ 'stakingMetrics'
+ );
- if (subStakingMetrics) {
- subStakingMetrics.subscribe();
- SubscriptionsController.remove(this.#network, 'stakingMetrics');
- }
+ if (subStakingMetrics) {
+ subStakingMetrics.subscribe();
+ SubscriptionsController.remove(this.#network, 'stakingMetrics');
+ }
- // Subscribe to staking metrics with new active era.
- SubscriptionsController.set(
+ // Subscribe to staking metrics with new active era.
+ SubscriptionsController.set(
+ this.#network,
+ 'stakingMetrics',
+ new StakingMetrics(
this.#network,
- 'stakingMetrics',
- new StakingMetrics(
- this.#network,
- this.activeEra,
- BigNumber.max(0, this.activeEra.index.minus(1))
- )
- );
+ this.activeEra,
+ BigNumber.max(0, this.activeEra.index.minus(1))
+ )
+ );
- document.dispatchEvent(
- new CustomEvent('new-active-era', {
- detail: { activeEra },
- })
- );
- }
- );
+ document.dispatchEvent(
+ new CustomEvent('new-active-era', {
+ detail: { activeEra },
+ })
+ );
+ });
this.#sub = sub;
}
} catch (e) {
diff --git a/packages/app/src/model/Subscribe/BlockNumber/index.ts b/packages/app/src/model/Subscribe/BlockNumber/index.ts
index 43b93fbe0..13d48f8e9 100644
--- a/packages/app/src/model/Subscribe/BlockNumber/index.ts
+++ b/packages/app/src/model/Subscribe/BlockNumber/index.ts
@@ -26,7 +26,10 @@ export class BlockNumber implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
- const unsub = pApi.query.System.Number.watchValue().subscribe((num) => {
+ const bestOrFinalized = 'best';
+ const unsub = pApi.query.System.Number.watchValue(
+ bestOrFinalized
+ ).subscribe((num) => {
// Update class block number.
this.blockNumber = num.toString();
diff --git a/packages/app/src/model/Subscribe/Bonded/index.tsx b/packages/app/src/model/Subscribe/Bonded/index.tsx
index 7e96e7780..25281319f 100644
--- a/packages/app/src/model/Subscribe/Bonded/index.tsx
+++ b/packages/app/src/model/Subscribe/Bonded/index.tsx
@@ -31,8 +31,10 @@ export class Bonded implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
const unsub = pApi.query.Staking.Bonded.watchValue(
- this.#address
+ this.#address,
+ bestOrFinalized
).subscribe((controller) => {
const account: BondedAccount = {
address: this.#address,
diff --git a/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
index 94237a35f..7248c5963 100644
--- a/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
+++ b/packages/app/src/model/Subscribe/FastUnstakeConfig/index.ts
@@ -27,9 +27,11 @@ export class FastUnstakeConfig implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
+
const sub = combineLatest([
- pApi.query.FastUnstake.Head.watchValue(),
- pApi.query.FastUnstake.CounterForQueue.watchValue(),
+ pApi.query.FastUnstake.Head.watchValue(bestOrFinalized),
+ pApi.query.FastUnstake.CounterForQueue.watchValue(bestOrFinalized),
]).subscribe(([head, counterForQueue]) => {
const config: FastUnstakeConfigResult = {
head,
diff --git a/packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts b/packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts
index 156b4e2a4..bb99f7509 100644
--- a/packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts
+++ b/packages/app/src/model/Subscribe/FastUnstakeQueue/index.ts
@@ -30,8 +30,10 @@ export class FastUnstakeQueue implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
const unsub = pApi.query.FastUnstake.Queue.watchValue(
- this.#address
+ this.#address,
+ bestOrFinalized
).subscribe((queue) => {
this.queue = queue;
diff --git a/packages/app/src/model/Subscribe/NetworkMetrics/index.ts b/packages/app/src/model/Subscribe/NetworkMetrics/index.ts
index 66728a7ff..20834c460 100644
--- a/packages/app/src/model/Subscribe/NetworkMetrics/index.ts
+++ b/packages/app/src/model/Subscribe/NetworkMetrics/index.ts
@@ -25,12 +25,17 @@ export class NetworkMetrics implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
const sub = combineLatest([
- pApi.query.Balances.TotalIssuance.watchValue(),
- pApi.query.Auctions.AuctionCounter.watchValue(),
- pApi.query.ParaSessionInfo.EarliestStoredSession.watchValue(),
- pApi.query.FastUnstake.ErasToCheckPerBlock.watchValue(),
- pApi.query.Staking.MinimumActiveStake.watchValue(),
+ pApi.query.Balances.TotalIssuance.watchValue(bestOrFinalized),
+ pApi.query.Auctions.AuctionCounter.watchValue(bestOrFinalized),
+ pApi.query.ParaSessionInfo.EarliestStoredSession.watchValue(
+ bestOrFinalized
+ ),
+ pApi.query.FastUnstake.ErasToCheckPerBlock.watchValue(
+ bestOrFinalized
+ ),
+ pApi.query.Staking.MinimumActiveStake.watchValue(bestOrFinalized),
]).subscribe(
([
totalIssuance,
diff --git a/packages/app/src/model/Subscribe/PoolsConfig/index.ts b/packages/app/src/model/Subscribe/PoolsConfig/index.ts
index 4977602e7..a15885ac3 100644
--- a/packages/app/src/model/Subscribe/PoolsConfig/index.ts
+++ b/packages/app/src/model/Subscribe/PoolsConfig/index.ts
@@ -28,17 +28,28 @@ export class PoolsConfig implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
const sub = combineLatest([
- pApi.query.NominationPools.CounterForPoolMembers.watchValue(),
- pApi.query.NominationPools.CounterForBondedPools.watchValue(),
- pApi.query.NominationPools.CounterForRewardPools.watchValue(),
- pApi.query.NominationPools.LastPoolId.watchValue(),
- pApi.query.NominationPools.MaxPoolMembers.watchValue(),
- pApi.query.NominationPools.MaxPoolMembersPerPool.watchValue(),
- pApi.query.NominationPools.MaxPools.watchValue(),
- pApi.query.NominationPools.MinCreateBond.watchValue(),
- pApi.query.NominationPools.MinJoinBond.watchValue(),
- pApi.query.NominationPools.GlobalMaxCommission.watchValue(),
+ pApi.query.NominationPools.CounterForPoolMembers.watchValue(
+ bestOrFinalized
+ ),
+ pApi.query.NominationPools.CounterForBondedPools.watchValue(
+ bestOrFinalized
+ ),
+ pApi.query.NominationPools.CounterForRewardPools.watchValue(
+ bestOrFinalized
+ ),
+ pApi.query.NominationPools.LastPoolId.watchValue(bestOrFinalized),
+ pApi.query.NominationPools.MaxPoolMembers.watchValue(bestOrFinalized),
+ pApi.query.NominationPools.MaxPoolMembersPerPool.watchValue(
+ bestOrFinalized
+ ),
+ pApi.query.NominationPools.MaxPools.watchValue(bestOrFinalized),
+ pApi.query.NominationPools.MinCreateBond.watchValue(bestOrFinalized),
+ pApi.query.NominationPools.MinJoinBond.watchValue(bestOrFinalized),
+ pApi.query.NominationPools.GlobalMaxCommission.watchValue(
+ bestOrFinalized
+ ),
]).subscribe(
([
counterForPoolMembers,
diff --git a/packages/app/src/model/Subscribe/StakingMetrics/index.ts b/packages/app/src/model/Subscribe/StakingMetrics/index.ts
index 221eac282..638ac9bbb 100644
--- a/packages/app/src/model/Subscribe/StakingMetrics/index.ts
+++ b/packages/app/src/model/Subscribe/StakingMetrics/index.ts
@@ -39,21 +39,25 @@ export class StakingMetrics implements Unsubscribable {
const { pApi } = ApiController.get(this.#network);
if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
const sub = combineLatest([
- pApi.query.Staking.CounterForValidators.watchValue(),
- pApi.query.Staking.MaxValidatorsCount.watchValue(),
- pApi.query.Staking.ValidatorCount.watchValue(),
+ pApi.query.Staking.CounterForValidators.watchValue(bestOrFinalized),
+ pApi.query.Staking.MaxValidatorsCount.watchValue(bestOrFinalized),
+ pApi.query.Staking.ValidatorCount.watchValue(bestOrFinalized),
pApi.query.Staking.ErasValidatorReward.watchValue(
- this.#previousEra.toString()
+ this.#previousEra.toString(),
+ bestOrFinalized
),
pApi.query.Staking.ErasTotalStake.watchValue(
- this.#previousEra.toString()
+ this.#previousEra.toString(),
+ bestOrFinalized
),
- pApi.query.Staking.MinNominatorBond.watchValue(),
+ pApi.query.Staking.MinNominatorBond.watchValue(bestOrFinalized),
pApi.query.Staking.ErasTotalStake.watchValue(
- this.#activeEra.index.toString()
+ this.#activeEra.index.toString(),
+ bestOrFinalized
),
- pApi.query.Staking.CounterForNominators.watchValue(),
+ pApi.query.Staking.CounterForNominators.watchValue(bestOrFinalized),
]).subscribe(
([
counterForValidators,
From c24eb3e3bc3861d5050ea0e2e0802cbc0c32aa5e Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 17:43:51 +0700
Subject: [PATCH 43/84] prepare `ActivePoolAccount` class
---
packages/app/src/contexts/Balances/index.tsx | 1 +
.../src/contexts/Pools/ActivePool/index.tsx | 1 +
.../src/controllers/Subscriptions/index.ts | 2 +-
.../src/controllers/Subscriptions/types.ts | 2 +
.../Subscribe/ActivePoolAccount/index.ts | 66 +++++++++++++++++++
5 files changed, 71 insertions(+), 1 deletion(-)
create mode 100644 packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
diff --git a/packages/app/src/contexts/Balances/index.tsx b/packages/app/src/contexts/Balances/index.tsx
index ab8087b0a..8b103f502 100644
--- a/packages/app/src/contexts/Balances/index.tsx
+++ b/packages/app/src/contexts/Balances/index.tsx
@@ -71,6 +71,7 @@ export const BalancesProvider = ({ children }: { children: ReactNode }) => {
});
if (peopleApi) {
ActivePoolsController.syncPools(
+ network,
api,
peopleApi,
peopleApiStatus,
diff --git a/packages/app/src/contexts/Pools/ActivePool/index.tsx b/packages/app/src/contexts/Pools/ActivePool/index.tsx
index 0669e0b67..c858403dd 100644
--- a/packages/app/src/contexts/Pools/ActivePool/index.tsx
+++ b/packages/app/src/contexts/Pools/ActivePool/index.tsx
@@ -101,6 +101,7 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
SyncController.dispatch('active-pools', 'syncing');
if (peopleApi) {
ActivePoolsController.syncPools(
+ network,
api,
peopleApi,
peopleApiStatus,
diff --git a/packages/app/src/controllers/Subscriptions/index.ts b/packages/app/src/controllers/Subscriptions/index.ts
index c71fa6552..b4f2cbdcb 100644
--- a/packages/app/src/controllers/Subscriptions/index.ts
+++ b/packages/app/src/controllers/Subscriptions/index.ts
@@ -45,7 +45,7 @@ export class SubscriptionsController {
// Sets a new subscription for a network.
static set(
- network: NetworkName,
+ network: NetworkName | SystemChainId,
subscriptionId: string,
subscription: Subscription
): void {
diff --git a/packages/app/src/controllers/Subscriptions/types.ts b/packages/app/src/controllers/Subscriptions/types.ts
index ded1ee291..41a612d6a 100644
--- a/packages/app/src/controllers/Subscriptions/types.ts
+++ b/packages/app/src/controllers/Subscriptions/types.ts
@@ -4,6 +4,7 @@
import type { AccountBalances } from 'model/Subscribe/AccountBalances';
import type { AccountProxies } from 'model/Subscribe/AccountProxies';
import type { ActiveEra } from 'model/Subscribe/ActiveEra';
+import type { ActivePoolAccount } from 'model/Subscribe/ActivePoolAccount';
import type { BlockNumber } from 'model/Subscribe/BlockNumber';
import type { Bonded } from 'model/Subscribe/Bonded';
import type { FastUnstakeConfig } from 'model/Subscribe/FastUnstakeConfig';
@@ -17,6 +18,7 @@ export type Subscription =
| AccountBalances
| AccountProxies
| ActiveEra
+ | ActivePoolAccount
| BlockNumber
| Bonded
| FastUnstakeConfig
diff --git a/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts b/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
new file mode 100644
index 000000000..25be11a0a
--- /dev/null
+++ b/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
@@ -0,0 +1,66 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { ActivePoolItem } from 'controllers/ActivePools/types';
+import { ApiController } from 'controllers/Api';
+import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import { combineLatest, type Subscription } from 'rxjs';
+import type { NetworkName, SystemChainId } from 'types';
+
+export class ActivePoolAccount implements Unsubscribable {
+ // The associated network for this instance.
+ #network: NetworkName | SystemChainId;
+
+ // Active subscription.
+ #sub: Subscription;
+
+ // Active pool item
+ #pool: ActivePoolItem;
+
+ constructor(network: NetworkName | SystemChainId, pool: ActivePoolItem) {
+ this.#network = network;
+ this.#pool = pool;
+ this.subscribe();
+ }
+
+ subscribe = async (): Promise => {
+ try {
+ const { pApi } = ApiController.get(this.#network);
+ const bestOrFinalized = 'best';
+
+ const sub = combineLatest([
+ pApi.query.NominationPools.BondedPools.watchValue(
+ this.#pool.id,
+ bestOrFinalized
+ ),
+ pApi.query.NominationPools.RewardPools.watchValue(
+ this.#pool.id,
+ bestOrFinalized
+ ),
+ pApi.query.System.Account.watchValue(
+ this.#pool.addresses.reward,
+ bestOrFinalized
+ ),
+ pApi.query.Staking.Nominators.watchValue(
+ this.#pool.addresses.stash,
+ bestOrFinalized
+ ),
+ ]).subscribe(async ([bondedPool, rewardPool, account, nominators]) => {
+ console.debug(bondedPool, rewardPool, account, nominators);
+
+ // TODO: Implement callback.
+ });
+
+ this.#sub = sub;
+ } catch (e) {
+ // Subscription failed.
+ }
+ };
+
+ // Unsubscribe from class subscription.
+ unsubscribe = (): void => {
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
+ }
+ };
+}
From 9a5632ffbbd0d6e76d7d7dc909528c79998d7325 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 18:57:22 +0700
Subject: [PATCH 44/84] remove "all roles" from Pool UI
---
packages/app/src/pages/Pools/Home/index.tsx | 31 ---------------------
1 file changed, 31 deletions(-)
diff --git a/packages/app/src/pages/Pools/Home/index.tsx b/packages/app/src/pages/Pools/Home/index.tsx
index 3b6bb253c..1771da4c1 100644
--- a/packages/app/src/pages/Pools/Home/index.tsx
+++ b/packages/app/src/pages/Pools/Home/index.tsx
@@ -9,8 +9,6 @@ import { CardWrapper } from 'library/Card/Wrappers';
import { PoolList } from 'library/PoolList';
import { StatBoxList } from 'library/StatBoxList';
import { useFavoritePools } from 'contexts/Pools/FavoritePools';
-import { useOverlay } from 'kits/Overlay/Provider';
-import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { PoolListProvider } from 'library/PoolList/context';
import { Roles } from '../Roles';
import { ClosurePrompts } from './ClosurePrompts';
@@ -23,34 +21,17 @@ import { MinCreateBondStat } from './Stats/MinCreateBond';
import { MinJoinBondStat } from './Stats/MinJoinBond';
import { Status } from './Status';
import { PoolsTabsProvider, usePoolsTabs } from './context';
-import { useActivePools } from 'hooks/useActivePools';
-import { useBalances } from 'contexts/Balances';
import { PageTitle, PageRow, RowSection } from 'ui-structure';
import { WithdrawPrompt } from 'library/WithdrawPrompt';
-import { useSyncing } from 'hooks/useSyncing';
import { useNetwork } from 'contexts/Network';
export const HomeInner = () => {
const { t } = useTranslation('pages');
const { network } = useNetwork();
const { favorites } = useFavoritePools();
- const { openModal } = useOverlay().modal;
const { bondedPools } = useBondedPools();
- const { getPoolMembership } = useBalances();
- const { poolMembersipSyncing } = useSyncing();
- const { activeAccount } = useActiveAccounts();
const { activeTab, setActiveTab } = usePoolsTabs();
const { getPoolRoles, activePool } = useActivePool();
- const membership = getPoolMembership(activeAccount);
-
- const { activePools } = useActivePools({
- who: activeAccount,
- });
-
- // Calculate the number of _other_ pools the user has a role in.
- const poolRoleCount = Object.keys(activePools).filter(
- (poolId) => poolId !== String(membership?.poolId)
- ).length;
const ROW_HEIGHT = 220;
@@ -81,18 +62,6 @@ export const HomeInner = () => {
badge: String(favorites.length),
},
]}
- button={
- !poolMembersipSyncing() && poolRoleCount > 0
- ? {
- title: t('pools.allRoles'),
- onClick: () =>
- openModal({
- key: 'AccountPoolRoles',
- options: { who: activeAccount, activePools },
- }),
- }
- : undefined
- }
/>
{activeTab === 0 && (
<>
From 8e73d757bf5d242ede369ee285a9cf4e20aa88c3 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 18:57:59 +0700
Subject: [PATCH 45/84] rm locales
---
packages/app/src/locale/cn/pages.json | 1 -
packages/app/src/locale/en/pages.json | 1 -
2 files changed, 2 deletions(-)
diff --git a/packages/app/src/locale/cn/pages.json b/packages/app/src/locale/cn/pages.json
index 6e0901e6b..569edeb87 100644
--- a/packages/app/src/locale/cn/pages.json
+++ b/packages/app/src/locale/cn/pages.json
@@ -138,7 +138,6 @@
"addressCopied": "地址已复制到剪贴板",
"addressInvalid": "地址无效",
"allPools": "所有提名池",
- "allRoles": "所有角色",
"assigned": "己分配",
"assignedToAnyAccount": " 您的主理人、提名人和守护人角色可以分配给任何帐户。",
"availableToClaim": "成员可申领的奖励{{unit}}金额",
diff --git a/packages/app/src/locale/en/pages.json b/packages/app/src/locale/en/pages.json
index dd80be38d..650175747 100644
--- a/packages/app/src/locale/en/pages.json
+++ b/packages/app/src/locale/en/pages.json
@@ -140,7 +140,6 @@
"addressCopied": "Address Copied to Clipboard",
"addressInvalid": "Address Invalid",
"allPools": "All Pools",
- "allRoles": "All Roles",
"assigned": "Assigned",
"assignedToAnyAccount": " Your Root, Nominator and Bouncer roles can be assigned to any account.",
"availableToClaim": "The outstanding amount of {{unit}} available to claim by pool members.",
From 29527860e1c40eb3fb8fb63518820cf0625ac967 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 20:19:03 +0700
Subject: [PATCH 46/84] init `ActivePoolAccount` subscription & remove multi
role logic
---
packages/app/src/contexts/Balances/index.tsx | 11 +-
.../src/contexts/Pools/ActivePool/index.tsx | 71 ++--
.../contexts/Pools/BondedPools/defaults.ts | 1 -
.../src/contexts/Pools/BondedPools/index.tsx | 64 ----
.../src/contexts/Pools/BondedPools/types.ts | 1 -
packages/app/src/contexts/Staking/index.tsx | 5 +
.../app/src/controllers/ActivePools/index.ts | 324 +++++-------------
.../app/src/hooks/useActivePools/index.tsx | 13 +-
.../Subscribe/ActivePoolAccount/index.ts | 131 ++++++-
9 files changed, 241 insertions(+), 380 deletions(-)
diff --git a/packages/app/src/contexts/Balances/index.tsx b/packages/app/src/contexts/Balances/index.tsx
index 8b103f502..7564d4fea 100644
--- a/packages/app/src/contexts/Balances/index.tsx
+++ b/packages/app/src/contexts/Balances/index.tsx
@@ -27,10 +27,10 @@ export const useBalances = () => useContext(BalancesContext);
export const BalancesProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
+ const { api, peopleApi } = useApi();
const { getBondedAccount } = useBonded();
const { accounts } = useImportedAccounts();
const createPoolAccounts = useCreatePoolAccounts();
- const { api, peopleApi, peopleApiStatus } = useApi();
const { activeAccount, activeProxy } = useActiveAccounts();
const controller = getBondedAccount(activeAccount);
@@ -70,14 +70,7 @@ export const BalancesProvider = ({ children }: { children: ReactNode }) => {
addresses: { ...createPoolAccounts(Number(poolId)) },
});
if (peopleApi) {
- ActivePoolsController.syncPools(
- network,
- api,
- peopleApi,
- peopleApiStatus,
- address,
- newPools
- );
+ ActivePoolsController.syncPools(network, address, newPools);
}
}
}
diff --git a/packages/app/src/contexts/Pools/ActivePool/index.tsx b/packages/app/src/contexts/Pools/ActivePool/index.tsx
index c858403dd..ae5f69890 100644
--- a/packages/app/src/contexts/Pools/ActivePool/index.tsx
+++ b/packages/app/src/contexts/Pools/ActivePool/index.tsx
@@ -3,12 +3,11 @@
import { setStateWithRef } from '@w3ux/utils';
import type { ReactNode } from 'react';
-import { createContext, useContext, useMemo, useRef, useState } from 'react';
+import { createContext, useContext, useRef, useState } from 'react';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import { useNetwork } from 'contexts/Network';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { useApi } from '../../Api';
-import { useBondedPools } from '../BondedPools';
import type { ActivePoolContextState } from './types';
import { useCreatePoolAccounts } from 'hooks/useCreatePoolAccounts';
import { useBalances } from 'contexts/Balances';
@@ -27,30 +26,15 @@ export const useActivePool = () => useContext(ActivePoolContext);
export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
const { getPoolMembership } = useBalances();
+ const { isReady, api, peopleApi } = useApi();
const { activeAccount } = useActiveAccounts();
const createPoolAccounts = useCreatePoolAccounts();
- const { isReady, api, peopleApi, peopleApiStatus } = useApi();
- const { getAccountPoolRoles, bondedPools } = useBondedPools();
const membership = getPoolMembership(activeAccount);
// Determine active pools to subscribe to. Dependencies of `activeAccount`, and `membership` mean
// that this object is only recalculated when these values change.
- const accountPoolIds = useMemo(() => {
- const rollPoolIds: string[] = Object.keys(
- getAccountPoolRoles(activeAccount) || {}
- );
-
- // If a membership subscription has resulted in an update that is inconsistent with
- // `bondedPools`, add that role to the list of the account's pool roles.
- if (
- membership?.poolId &&
- !rollPoolIds.includes(String(membership.poolId))
- ) {
- rollPoolIds.push(String(membership.poolId));
- }
- return rollPoolIds;
- }, [activeAccount, bondedPools, membership]);
+ const accountPoolId = membership?.poolId ? String(membership.poolId) : null;
// Store the currently selected active pool for the UI. Should default to the membership pool if
// present. Used in event callback, therefore needs an accompanying ref.
@@ -64,27 +48,21 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
// Only listen to the active account's active pools, otherwise return an empty array. NOTE:
// `activePoolsRef` is needed to check if the pool has changed after the async call of fetching
// pending rewards.
- const { getActivePools, activePoolsRef, getPoolNominations } = useActivePools(
- {
- who: activeAccount,
- onCallback: async () => {
- // Sync: active pools synced once all account pools have been reported.
- if (
- accountPoolIds.length <=
- ActivePoolsController.getPools(activeAccount).length
- ) {
- SyncController.dispatch('active-pools', 'complete');
- }
- },
- }
- );
+ const { getActivePool, activePoolsRef, getPoolNominations } = useActivePools({
+ who: activeAccount,
+ onCallback: async () => {
+ if (ActivePoolsController.getPool(network, activeAccount)) {
+ SyncController.dispatch('active-pools', 'complete');
+ }
+ },
+ });
// Store the currently active pool's pending rewards for the active account.
const [pendingPoolRewards, setPendingPoolRewards] = useState(
new BigNumber(0)
);
- const activePool = activePoolId ? getActivePools(activePoolId) : null;
+ const activePool = activePoolId ? getActivePool(activePoolId) : null;
const activePoolNominations = activePoolId
? getPoolNominations(activePoolId)
@@ -92,22 +70,17 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
// Sync active pool subscriptions.
const syncActivePoolSubscriptions = async () => {
- if (api && accountPoolIds.length) {
- const newActivePools = accountPoolIds.map((pool) => ({
- id: pool,
- addresses: { ...createPoolAccounts(Number(pool)) },
- }));
+ if (api && accountPoolId) {
+ const newActivePool = [
+ {
+ id: accountPoolId,
+ addresses: { ...createPoolAccounts(Number(accountPoolId)) },
+ },
+ ];
SyncController.dispatch('active-pools', 'syncing');
if (peopleApi) {
- ActivePoolsController.syncPools(
- network,
- api,
- peopleApi,
- peopleApiStatus,
- activeAccount,
- newActivePools
- );
+ ActivePoolsController.syncPools(network, activeAccount, newActivePool);
}
} else {
// No active pools to sync. Mark as complete.
@@ -119,7 +92,7 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
const assignActivePoolId = () => {
// Membership takes priority, followed by the first pool the account has a role in. Falls back
// to `null` if no active roles are found.
- const initialActivePoolId = membership?.poolId || accountPoolIds[0] || null;
+ const initialActivePoolId = membership?.poolId || null;
if (initialActivePoolId && !activePool) {
setActivePoolId(String(initialActivePoolId));
}
@@ -235,7 +208,7 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
syncActivePoolSubscriptions();
assignActivePoolId();
}
- }, [network, isReady, accountPoolIds]);
+ }, [network, isReady, membership]);
// Reset on network change and component unmount. NOTE: ActivePoolsController also unsubscribes on
// network change; this is handled by the Api instance.
diff --git a/packages/app/src/contexts/Pools/BondedPools/defaults.ts b/packages/app/src/contexts/Pools/BondedPools/defaults.ts
index 0363dc217..5430aebb6 100644
--- a/packages/app/src/contexts/Pools/BondedPools/defaults.ts
+++ b/packages/app/src/contexts/Pools/BondedPools/defaults.ts
@@ -12,7 +12,6 @@ export const defaultBondedPoolsContext: BondedPoolsContextState = {
removeFromBondedPools: (poolId) => {},
getPoolNominationStatus: (nominator, address) => {},
getPoolNominationStatusCode: (statuses) => '',
- getAccountPoolRoles: (address) => null,
replacePoolRoles: (poolId, roleEdits) => {},
poolSearchFilter: (filteredPools, searchTerm) => [],
bondedPools: [],
diff --git a/packages/app/src/contexts/Pools/BondedPools/index.tsx b/packages/app/src/contexts/Pools/BondedPools/index.tsx
index 12d2b283f..71c72e9b9 100644
--- a/packages/app/src/contexts/Pools/BondedPools/index.tsx
+++ b/packages/app/src/contexts/Pools/BondedPools/index.tsx
@@ -6,7 +6,6 @@ import { setStateWithRef, shuffle } from '@w3ux/utils';
import type { ReactNode } from 'react';
import { createContext, useContext, useRef, useState } from 'react';
import type {
- AccountPoolRoles,
BondedPool,
BondedPoolsContextState,
MaybePool,
@@ -284,68 +283,6 @@ export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
}
};
- // Gets all pools that the account has a role in. Returns an object with each pool role as keys,
- // and array of pool ids as their values.
- const accumulateAccountPoolRoles = (who: MaybeAddress): AccountPoolRoles => {
- if (!who) {
- return {
- root: [],
- depositor: [],
- nominator: [],
- bouncer: [],
- };
- }
-
- const depositor = bondedPoolsRef.current
- .filter((b) => b.roles.depositor === who)
- .map((b) => b.id);
-
- const root = bondedPoolsRef.current
- .filter((b: BondedPool) => b.roles.root === who)
- .map((b) => b.id);
-
- const nominator = bondedPoolsRef.current
- .filter((b) => b.roles.nominator === who)
- .map((b) => b.id);
-
- const bouncer = bondedPoolsRef.current
- .filter((b) => b.roles.bouncer === who)
- .map((b) => b.id);
-
- const result = {
- root,
- depositor,
- nominator,
- bouncer,
- };
-
- return result;
- };
-
- // Gets a list of roles for all the pools the provided account has one or more roles in.
- const getAccountPoolRoles = (who: MaybeAddress) => {
- const allAccountRoles = accumulateAccountPoolRoles(who);
-
- // Reformat all roles object, keyed by pool id.
- const pools: Record = {};
-
- if (allAccountRoles) {
- Object.entries(allAccountRoles).forEach(([role, poolIds]) => {
- poolIds.forEach((poolId) => {
- const exists = Object.keys(pools).find(
- (k) => String(k) === String(poolId)
- );
- if (!exists) {
- pools[poolId] = [role];
- } else {
- pools[poolId].push(role);
- }
- });
- });
- }
- return pools;
- };
-
// Determine roles to replace from roleEdits
const toReplace = (roleEdits: AnyJson) => {
const root = roleEdits?.root?.newAddress ?? '';
@@ -415,7 +352,6 @@ export const BondedPoolsProvider = ({ children }: { children: ReactNode }) => {
removeFromBondedPools,
getPoolNominationStatus,
getPoolNominationStatusCode,
- getAccountPoolRoles,
replacePoolRoles,
poolSearchFilter,
bondedPools,
diff --git a/packages/app/src/contexts/Pools/BondedPools/types.ts b/packages/app/src/contexts/Pools/BondedPools/types.ts
index 87af9c7af..62b669b3b 100644
--- a/packages/app/src/contexts/Pools/BondedPools/types.ts
+++ b/packages/app/src/contexts/Pools/BondedPools/types.ts
@@ -18,7 +18,6 @@ export interface BondedPoolsContextState {
address: MaybeAddress
) => AnyApi;
getPoolNominationStatusCode: (statuses: NominationStatuses | null) => string;
- getAccountPoolRoles: (address: MaybeAddress) => AnyApi;
replacePoolRoles: (poolId: number, roleEdits: AnyJson) => void;
poolSearchFilter: (filteredPools: AnyFilter, searchTerm: string) => AnyJson[];
bondedPools: BondedPool[];
diff --git a/packages/app/src/contexts/Staking/index.tsx b/packages/app/src/contexts/Staking/index.tsx
index f6f682619..1a84bd4c7 100644
--- a/packages/app/src/contexts/Staking/index.tsx
+++ b/packages/app/src/contexts/Staking/index.tsx
@@ -249,6 +249,11 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
// NOTE: Only one page is fetched for each validator for now.
const page = pages[0];
+ // NOTE: Some pages turn up as undefined - might be worth exploring further.
+ if (!page) {
+ continue;
+ }
+
const {
keyArgs,
value: { others },
diff --git a/packages/app/src/controllers/ActivePools/index.ts b/packages/app/src/controllers/ActivePools/index.ts
index 7ff42f010..c501c76ba 100644
--- a/packages/app/src/controllers/ActivePools/index.ts
+++ b/packages/app/src/controllers/ActivePools/index.ts
@@ -1,49 +1,28 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
-import { defaultPoolNominations } from 'contexts/Pools/ActivePool/defaults';
-import type { ActivePool, PoolRoles } from 'contexts/Pools/ActivePool/types';
-import { IdentitiesController } from 'controllers/Identities';
-import type { AnyApi, MaybeAddress } from 'types';
+import type { MaybeAddress, NetworkName, SystemChainId } from 'types';
import type {
AccountActivePools,
AccountPoolNominations,
- AccountUnsubs,
ActivePoolItem,
DetailActivePool,
} from './types';
import { SyncController } from 'controllers/Sync';
-import type { Nominations } from 'contexts/Balances/types';
-import type { ApiPromise } from '@polkadot/api';
+import { SubscriptionsController } from 'controllers/Subscriptions';
+import { ActivePoolAccount } from 'model/Subscribe/ActivePoolAccount';
+import { defaultPoolNominations } from 'contexts/Pools/ActivePool/defaults';
export class ActivePoolsController {
- // ------------------------------------------------------
- // Class members.
- // ------------------------------------------------------
-
// Pool ids that are being subscribed to. Keyed by address.
static pools: Record = {};
- // Active pools that are being returned from subscriptions, keyed by account address, then pool
- // id.
- static activePools: Record = {};
-
- // Active pool nominations, keyed by account address, then pool id.
- static poolNominations: Record = {};
-
- // Unsubscribe objects, keyed by account address, then pool id.
- static #unsubs: Record = {};
-
- // ------------------------------------------------------
- // Pool membership syncing.
- // ------------------------------------------------------
+ // Map from an address to its associated pool ids
+ static addressToPool: Record = {};
- // Subscribes to pools and unsubscribes from removed pools.
+ // Subscribes to new pools and unsubscribes from removed pools.
static syncPools = async (
- api: ApiPromise,
- peopleApi: ApiPromise,
- peopleApiStatus: string,
+ network: NetworkName,
address: MaybeAddress,
newPools: ActivePoolItem[]
): Promise => {
@@ -52,260 +31,125 @@ export class ActivePoolsController {
}
// Handle pools that have been removed.
- this.handleRemovedPools(address, newPools);
+ this.handleRemovedPools(network, address);
- const currentPools = this.getPools(address);
+ const currentPool = this.addressToPool[address];
// Determine new pools that need to be subscribed to.
- const poolsAdded = newPools.filter(
- (newPool) => !currentPools.find(({ id }) => id === newPool.id)
- );
+ const updatedPool = newPools.find((newPool) => currentPool === newPool.id)
+ ? false
+ : newPools[0];
- if (poolsAdded.length) {
- // Subscribe to and add new pool data.
- poolsAdded.forEach(async (pool) => {
- this.pools[address] = currentPools.concat(pool);
+ if (updatedPool) {
+ this.pools[address] = newPools;
- const unsub = await api.queryMulti(
- [
- [api.query.nominationPools.bondedPools, pool.id],
- [api.query.nominationPools.rewardPools, pool.id],
- [api.query.system.account, pool.addresses.reward],
- [api.query.staking.nominators, pool.addresses.stash],
- ],
- async ([
- bondedPool,
- rewardPool,
- accountData,
- nominators,
- ]): Promise => {
- // NOTE: async: fetches identity data for roles.
- await this.handleActivePoolCallback(
- peopleApi,
- peopleApiStatus,
- address,
- pool,
- bondedPool,
- rewardPool,
- accountData
- );
- this.handleNominatorsCallback(address, pool, nominators);
+ // Subscribe to and add new pool data.
+ SubscriptionsController.set(
+ network,
+ `activePool-${address}-${updatedPool.id}`,
+ new ActivePoolAccount(network, address, updatedPool)
+ );
- if (
- this.activePools?.[address]?.[pool.id] &&
- this.poolNominations?.[address]?.[pool.id]
- ) {
- document.dispatchEvent(
- new CustomEvent('new-active-pool', {
- detail: {
- address,
- pool: this.activePools[address][pool.id],
- nominations: this.poolNominations[address][pool.id],
- },
- })
- );
- }
- }
- );
- this.setUnsub(address, pool.id, unsub);
- });
+ // Add pool id to address mapping.
+ this.addressToPool[address] = updatedPool.id;
} else {
// Status: Pools Synced Completed.
SyncController.dispatch('active-pools', 'complete');
}
};
- // Handle active pool callback.
- static handleActivePoolCallback = async (
- peopleApi: ApiPromise,
- peopleApiStatus: string,
- address: string,
- pool: ActivePoolItem,
- bondedPoolResult: AnyApi,
- rewardPoolResult: AnyApi,
- accountDataResult: AnyApi
- ): Promise => {
- const bondedPool = bondedPoolResult?.unwrapOr(undefined)?.toHuman();
- const rewardPool = rewardPoolResult?.unwrapOr(undefined)?.toHuman();
- const balance = accountDataResult.data;
- const rewardAccountBalance = balance?.free.toString();
-
- if (peopleApi && peopleApiStatus === 'ready') {
- // Fetch identities for roles and expand `bondedPool` state to store them.
- bondedPool.roleIdentities = await IdentitiesController.fetch(
- peopleApi,
- this.getUniqueRoleAddresses(bondedPool.roles)
- );
- }
-
- // Only persist the active pool to class state (and therefore dispatch an event) if both the
- // bonded pool and reward pool are returned.
- if (bondedPool && rewardPool) {
- const newPool = {
- id: Number(pool.id),
- addresses: pool.addresses,
- bondedPool,
- rewardPool,
- rewardAccountBalance,
- };
-
- this.setActivePool(address, pool.id, newPool);
- } else {
- // Invalid pools were returned. To signal pool was synced, set active pool to `null`.
- this.setActivePool(address, pool.id, null);
- }
- };
-
- // Handle nominators callback.
- static handleNominatorsCallback = (
- address: string,
- pool: ActivePoolItem,
- nominatorsResult: AnyApi
- ): void => {
- const maybeNewNominations = nominatorsResult.unwrapOr(null);
-
- const newNominations: Nominations =
- maybeNewNominations === null
- ? defaultPoolNominations
- : {
- targets: maybeNewNominations.targets.toHuman(),
- submittedIn: maybeNewNominations.submittedIn.toHuman(),
- };
-
- this.setPoolNominations(address, pool.id, newNominations);
- };
-
// Remove pools that no longer exist.
static handleRemovedPools = (
- address: string,
- newPools: ActivePoolItem[]
+ network: NetworkName | SystemChainId,
+ address: string
): void => {
- const currentPools = this.getPools(address);
-
- // Determine removed pools - current ones that no longer exist in `newPools`.
- const poolsRemoved = currentPools.filter(
- (pool) => !newPools.find((newPool) => newPool.id === pool.id)
- );
-
- // Unsubscribe from removed pool subscriptions.
- poolsRemoved.forEach((pool) => {
- if (this.#unsubs?.[address]?.[pool.id]) {
- this.#unsubs[address][pool.id]();
- }
- delete this.activePools[address][pool.id];
- delete this.poolNominations[address][pool.id];
- });
+ const currentPool = this.addressToPool[address];
- // Remove removed pools from class.
- this.pools[address] = currentPools.filter(
- (pool) => !poolsRemoved.includes(pool)
- );
+ if (currentPool) {
+ // Unsubscribe from removed pool subscription.
+ SubscriptionsController.remove(
+ network,
+ `activePool-${address}-${currentPool}`
+ );
- // Tidy up empty class state.
- if (!this.pools[address].length) {
+ // Remove pool from class.
+ delete this.addressToPool[address];
delete this.pools[address];
}
-
- if (!this.activePools[address]) {
- delete this.activePools[address];
- }
-
- if (!this.poolNominations[address]) {
- delete this.poolNominations[address];
- }
- if (!this.#unsubs[address]) {
- delete this.#unsubs[address];
- }
- };
-
- // ------------------------------------------------------
- // Subscription handling.
- // ------------------------------------------------------
-
- // Unsubscribe from all subscriptions and reset class members.
- static unsubscribe = (): void => {
- Object.values(this.#unsubs).forEach((accountUnsubs) => {
- Object.values(accountUnsubs).forEach((unsub) => {
- unsub();
- });
- });
-
- this.#unsubs = {};
};
// ------------------------------------------------------
// Getters.
// ------------------------------------------------------
- // Gets pools for a provided address.
- static getPools = (address: MaybeAddress): ActivePoolItem[] => {
+ // Gets pool for a provided address.
+ static getPool = (
+ network: NetworkName,
+ address: MaybeAddress
+ ): ActivePoolItem | undefined => {
if (!address) {
- return [];
+ return undefined;
}
- return this.pools?.[address] || [];
+ const activePoolAccount = SubscriptionsController.get(
+ network,
+ `activePool-${address}-${this.addressToPool[address]}`
+ ) as ActivePoolAccount;
+
+ return activePoolAccount?.pool || undefined;
};
- // Gets active pools for a provided address.
- static getActivePools = (address: MaybeAddress): AccountActivePools => {
+ // Gets active pool for a provided address.
+ static getActivePool = (
+ network: NetworkName,
+ address: MaybeAddress
+ ): AccountActivePools => {
if (!address) {
return {};
}
- return this.activePools?.[address] || {};
+ const poolId = this.addressToPool[address];
+ const activePool = SubscriptionsController.get(
+ network,
+ `activePool-${address}-${poolId}`
+ ) as ActivePoolAccount;
+
+ if (!activePool) {
+ return {};
+ }
+
+ return { [poolId]: activePool?.activePool || null };
};
// Gets active pool nominations for a provided address.
static getPoolNominations = (
+ network: NetworkName,
address: MaybeAddress
): AccountPoolNominations => {
if (!address) {
return {};
}
- return this.poolNominations?.[address] || {};
- };
-
- // Gets unique role addresses from a bonded pool's `roles` record.
- static getUniqueRoleAddresses = (roles: PoolRoles): string[] => {
- const roleAddresses: string[] = [
- ...new Set(Object.values(roles).filter((role) => role !== undefined)),
- ];
- return roleAddresses;
+ const poolId = this.addressToPool[address];
+ const activePool = SubscriptionsController.get(
+ network,
+ `activePool-${address}-${poolId}`
+ ) as ActivePoolAccount;
+
+ return {
+ poolId: activePool?.poolNominations || defaultPoolNominations,
+ };
};
- // ------------------------------------------------------
- // Setters.
- // ------------------------------------------------------
-
- // Set an active pool for an address.
- static setActivePool = (
- address: string,
- poolId: string,
- activePool: ActivePool | null
- ): void => {
- if (!this.activePools[address]) {
- this.activePools[address] = {};
- }
- this.activePools[address][poolId] = activePool;
- };
-
- // Set pool nominations for an address.
- static setPoolNominations = (
- address: string,
- poolId: string,
- nominations: Nominations
- ): void => {
- if (!this.poolNominations[address]) {
- this.poolNominations[address] = {};
- }
- this.poolNominations[address][poolId] = nominations;
- };
-
- // Set unsub for an address and pool id.
- static setUnsub = (address: string, poolId: string, unsub: VoidFn): void => {
- if (!this.#unsubs[address]) {
- this.#unsubs[address] = {};
- }
- this.#unsubs[address][poolId] = unsub;
- };
+ // Gets all active pools for a provided network.
+ static getAllActivePools = (network: NetworkName) =>
+ Object.fromEntries(
+ Object.entries(this.addressToPool).map(([addr, poolId]) => {
+ const activePoolAccount = SubscriptionsController.get(
+ network,
+ `activePool-${addr}-${poolId}`
+ ) as ActivePoolAccount;
+
+ return [poolId, activePoolAccount?.activePool || null];
+ })
+ );
// ------------------------------------------------------
// Class helpers.
diff --git a/packages/app/src/hooks/useActivePools/index.tsx b/packages/app/src/hooks/useActivePools/index.tsx
index 2e52e3ac0..14973a490 100644
--- a/packages/app/src/hooks/useActivePools/index.tsx
+++ b/packages/app/src/hooks/useActivePools/index.tsx
@@ -18,14 +18,14 @@ export const useActivePools = ({ onCallback, who }: ActivePoolsProps) => {
// Stores active pools.
const [activePools, setActivePools] = useState(
- ActivePoolsController.getActivePools(who)
+ ActivePoolsController.getActivePool(network, who)
);
const activePoolsRef = useRef(activePools);
// Store nominations of active pools.
const [poolNominations, setPoolNominations] =
useState(
- ActivePoolsController.getPoolNominations(who)
+ ActivePoolsController.getPoolNominations(network, who)
);
const poolNominationsRef = useRef(poolNominations);
@@ -58,7 +58,8 @@ export const useActivePools = ({ onCallback, who }: ActivePoolsProps) => {
};
// Get an active pool.
- const getActivePools = (poolId: string) => activePools?.[poolId] || null;
+ const getActivePool = (poolId: string) =>
+ activePools?.[Number(poolId)] || null;
// Get an active pool's nominations.
const getPoolNominations = (poolId: string) =>
@@ -73,12 +74,12 @@ export const useActivePools = ({ onCallback, who }: ActivePoolsProps) => {
// Update state on account change.
useEffect(() => {
setStateWithRef(
- ActivePoolsController.getActivePools(who),
+ ActivePoolsController.getActivePool(network, who),
setActivePools,
activePoolsRef
);
setStateWithRef(
- ActivePoolsController.getPoolNominations(who),
+ ActivePoolsController.getPoolNominations(network, who),
setPoolNominations,
poolNominationsRef
);
@@ -91,7 +92,7 @@ export const useActivePools = ({ onCallback, who }: ActivePoolsProps) => {
return {
activePools,
activePoolsRef,
- getActivePools,
+ getActivePool,
getPoolNominations,
};
};
diff --git a/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts b/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
index 25be11a0a..9f3410c3d 100644
--- a/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
+++ b/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
@@ -1,11 +1,15 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
+import type { Nominations } from 'contexts/Balances/types';
+import { defaultPoolNominations } from 'contexts/Pools/ActivePool/defaults';
+import type { ActivePool, PoolRoles } from 'contexts/Pools/ActivePool/types';
import type { ActivePoolItem } from 'controllers/ActivePools/types';
import { ApiController } from 'controllers/Api';
import type { Unsubscribable } from 'controllers/Subscriptions/types';
+import type { PapiApi } from 'model/Api/types';
import { combineLatest, type Subscription } from 'rxjs';
-import type { NetworkName, SystemChainId } from 'types';
+import type { AnyApi, NetworkName, SystemChainId } from 'types';
export class ActivePoolAccount implements Unsubscribable {
// The associated network for this instance.
@@ -15,40 +19,73 @@ export class ActivePoolAccount implements Unsubscribable {
#sub: Subscription;
// Active pool item
- #pool: ActivePoolItem;
+ pool: ActivePoolItem;
- constructor(network: NetworkName | SystemChainId, pool: ActivePoolItem) {
+ // Address associated with this pool.
+ address: string;
+
+ // Active pool of the address.
+ activePool: ActivePool | null;
+
+ // Active pool nominations.
+ poolNominations: Nominations;
+
+ constructor(
+ network: NetworkName | SystemChainId,
+ address: string,
+ pool: ActivePoolItem
+ ) {
this.#network = network;
- this.#pool = pool;
+ this.pool = pool;
+ this.address = address;
this.subscribe();
}
subscribe = async (): Promise => {
try {
const { pApi } = ApiController.get(this.#network);
+ const { pApi: peopleApi } = ApiController.get(
+ `people-${this.#network}` as SystemChainId
+ );
const bestOrFinalized = 'best';
const sub = combineLatest([
pApi.query.NominationPools.BondedPools.watchValue(
- this.#pool.id,
+ this.pool.id,
bestOrFinalized
),
pApi.query.NominationPools.RewardPools.watchValue(
- this.#pool.id,
+ this.pool.id,
bestOrFinalized
),
pApi.query.System.Account.watchValue(
- this.#pool.addresses.reward,
+ this.pool.addresses.reward,
bestOrFinalized
),
pApi.query.Staking.Nominators.watchValue(
- this.#pool.addresses.stash,
+ this.pool.addresses.stash,
bestOrFinalized
),
]).subscribe(async ([bondedPool, rewardPool, account, nominators]) => {
- console.debug(bondedPool, rewardPool, account, nominators);
+ await this.handleActivePoolCallback(
+ peopleApi,
+ bondedPool,
+ rewardPool,
+ account
+ );
+ this.handleNominatorsCallback(nominators);
- // TODO: Implement callback.
+ if (this.activePool && this.poolNominations) {
+ document.dispatchEvent(
+ new CustomEvent('new-active-pool', {
+ detail: {
+ address: this.address,
+ pool: this.activePool,
+ nominations: this.poolNominations,
+ },
+ })
+ );
+ }
});
this.#sub = sub;
@@ -57,6 +94,80 @@ export class ActivePoolAccount implements Unsubscribable {
}
};
+ // Handle active pool callback.
+ handleActivePoolCallback = async (
+ peopleApi: PapiApi,
+ bondedPool: AnyApi,
+ rewardPool: AnyApi,
+ account: AnyApi
+ ): Promise => {
+ const balance = account.data;
+ const rewardAccountBalance = balance?.free.toString();
+
+ if (peopleApi) {
+ // Fetch identities for roles and expand `bondedPool` state to store them.
+ // TODO: IdentitiesController migrate to PapiApi.
+ // bondedPool.roleIdentities = await IdentitiesController.fetch(
+ // peopleApi,
+ // this.getUniqueRoleAddresses(bondedPool.roles)
+ // );
+ }
+
+ const bondedPoolFormatted = {
+ points: bondedPool.points.toString(),
+ memberCounter: bondedPool.member_counter.toString(),
+ roles: bondedPool.roles,
+ roleIdentities: bondedPool.roleIdentities,
+ state: bondedPool.state.type,
+ };
+
+ const rewardPoolFormatted = {
+ lastRecordedRewardCounter:
+ rewardPool.last_recorded_reward_counter.toString(),
+ lastRecordedTotalPayouts:
+ rewardPool.last_recorded_total_payouts.toString(),
+ totalCommissionClaimed: rewardPool.total_commission_claimed.toString(),
+ totalCommissionPending: rewardPool.total_commission_pending.toString(),
+ totalRewardsClaimed: rewardPool.total_rewards_claimed.toString(),
+ };
+
+ // Only persist the active pool to class state (and therefore dispatch an event) if both the
+ // bonded pool and reward pool are returned.
+ if (bondedPool && rewardPool) {
+ const newPool = {
+ id: Number(this.pool.id),
+ addresses: this.pool.addresses,
+ bondedPool: bondedPoolFormatted,
+ rewardPool: rewardPoolFormatted,
+ rewardAccountBalance,
+ };
+
+ this.activePool = newPool;
+ } else {
+ // Invalid pools were returned. To signal pool was synced, set active pool to `null`.
+ this.activePool = null;
+ }
+ };
+
+ // Handle nominators callback.
+ handleNominatorsCallback = (nominators: AnyApi): void => {
+ const newNominations: Nominations = !nominators
+ ? defaultPoolNominations
+ : {
+ targets: nominators.targets,
+ submittedIn: nominators.submitted_in,
+ };
+ this.poolNominations = newNominations;
+ };
+
+ // Gets unique role addresses from a bonded pool's `roles` record.
+ getUniqueRoleAddresses = (roles: PoolRoles): string[] => {
+ const roleAddresses: string[] = [
+ ...new Set(Object.values(roles).filter((role) => role !== undefined)),
+ ];
+ return roleAddresses;
+ };
+
// Unsubscribe from class subscription.
unsubscribe = (): void => {
if (typeof this.#sub?.unsubscribe === 'function') {
From 248076489070543c6c5d035b30ec640376064ef4 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 20:50:41 +0700
Subject: [PATCH 47/84] migrate `IdentitiesController` to `pApi`
---
.../Validators/ValidatorEntries/index.tsx | 8 ++--
.../app/src/controllers/Identities/index.ts | 40 ++++++++++---------
.../src/hooks/useValidatorFilters/index.tsx | 4 +-
.../ValidatorList/ValidatorItem/Utils.tsx | 4 +-
.../src/model/Query/IdentityOfMulti/index.ts | 1 -
.../app/src/model/Query/SuperOfMulti/index.ts | 28 +++++++++++++
.../Subscribe/ActivePoolAccount/index.ts | 10 ++---
7 files changed, 64 insertions(+), 31 deletions(-)
create mode 100644 packages/app/src/model/Query/SuperOfMulti/index.ts
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index ac54c395c..57e4dd0a1 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -5,7 +5,7 @@ import { rmCommas, shuffle } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import { createContext, useContext, useEffect, useRef, useState } from 'react';
-import type { AnyApi, Fn } from 'types';
+import type { AnyApi, Fn, SystemChainId } from 'types';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import { useNetwork } from 'contexts/Network';
import { useApi } from 'contexts/Api';
@@ -322,11 +322,13 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
setAvgCommission(avg);
// NOTE: validators are shuffled before committed to state.
setValidators(shuffle(validatorEntries));
-
+ const { pApi: peoplePapiApi } = ApiController.get(
+ `people-${network}` as SystemChainId
+ );
if (peopleApi && peopleApiStatus === 'ready') {
const addresses = validatorEntries.map(({ address }) => address);
const { identities, supers } = await IdentitiesController.fetch(
- peopleApi,
+ peoplePapiApi,
addresses
);
setValidatorIdentities(identities);
diff --git a/packages/app/src/controllers/Identities/index.ts b/packages/app/src/controllers/Identities/index.ts
index a4a4c14a7..43a2a7519 100644
--- a/packages/app/src/controllers/Identities/index.ts
+++ b/packages/app/src/controllers/Identities/index.ts
@@ -2,21 +2,23 @@
// SPDX-License-Identifier: GPL-3.0-only
import type { AnyApi } from 'types';
-import type { ApiPromise } from '@polkadot/api';
import type { AnyJson } from '@w3ux/types';
+import type { PapiApi } from 'model/Api/types';
+import { IdentityOfMulti } from 'model/Query/IdentityOfMulti';
+import { SuperOfMulti } from 'model/Query/SuperOfMulti';
export class IdentitiesController {
- static fetch = async (api: ApiPromise, addresses: string[]) => {
+ static fetch = async (pApi: PapiApi, addresses: string[]) => {
// Fetches identities for addresses.
const fetchBase = async () => {
- const result = (await api.query.identity.identityOf.multi(addresses)).map(
- (identity) => identity.toHuman()
- );
+ const addressesMulti: [string][] = addresses.map((address) => [address]);
+ const result = await new IdentityOfMulti(pApi, addressesMulti).fetch();
// Take identity data (first index) of results.
- const data = result.map(
- (resultArray: AnyJson | null) => resultArray?.[0] || null
- );
+ const data =
+ result?.map(
+ (resultArray: AnyJson | null) => resultArray?.[0] || null
+ ) || [];
return Object.fromEntries(
data
@@ -27,26 +29,28 @@ export class IdentitiesController {
// Fetch an array of super accounts and their identities.
const fetchSupers = async () => {
- const supersRaw = (await api.query.identity.superOf.multi(addresses)).map(
- (superOf) => superOf.toHuman()
- );
+ const addressesMulti: [string][] = addresses.map((address) => [address]);
+ const supersRawMulti = await new SuperOfMulti(
+ pApi,
+ addressesMulti
+ ).fetch();
const supers = Object.fromEntries(
- supersRaw
+ (supersRawMulti || [])
.map((k, i) => [
addresses[i],
{
superOf: k,
},
])
- .filter(([, { superOf }]: AnyApi) => superOf !== null)
+ .filter(([, { superOf }]: AnyApi) => superOf !== undefined)
);
- const superIdentities = (
- await api.query.identity.identityOf.multi(
- Object.values(supers).map(({ superOf }: AnyApi) => superOf[0])
- )
- ).map((superIdentity) => superIdentity.toHuman());
+ const superOfMulti: [string][] = Object.values(supers).map(
+ ({ superOf }: AnyApi) => [superOf[0]]
+ );
+ const superIdentities =
+ (await new IdentityOfMulti(pApi, superOfMulti).fetch()) || [];
// Take identity data (first index) of results.
const data = superIdentities.map(
diff --git a/packages/app/src/hooks/useValidatorFilters/index.tsx b/packages/app/src/hooks/useValidatorFilters/index.tsx
index 82a659bc6..6e6ff6c58 100644
--- a/packages/app/src/hooks/useValidatorFilters/index.tsx
+++ b/packages/app/src/hooks/useValidatorFilters/index.tsx
@@ -211,7 +211,7 @@ export const useValidatorFilters = () => {
const filteredList: AnyFilter = [];
for (const validator of list) {
const identity = validatorIdentities[validator.address] ?? '';
- const identityRaw = identity?.info?.display?.Raw ?? '';
+ const identityRaw = identity?.info?.display?.value?.asText() ?? '';
const identityAsBytes = u8aToString(u8aUnwrapBytes(identityRaw));
const identitySearch = (
identityAsBytes === '' ? identityRaw : identityAsBytes
@@ -219,7 +219,7 @@ export const useValidatorFilters = () => {
const superIdentity = validatorSupers[validator.address] ?? null;
const superIdentityRaw =
- superIdentity?.identity?.info?.display?.Raw ?? '';
+ superIdentity?.identity?.info?.display?.value?.asText() ?? '';
const superIdentityAsBytes = u8aToString(
u8aUnwrapBytes(superIdentityRaw)
);
diff --git a/packages/app/src/library/ValidatorList/ValidatorItem/Utils.tsx b/packages/app/src/library/ValidatorList/ValidatorItem/Utils.tsx
index 184e6c34e..fe5b08a1e 100644
--- a/packages/app/src/library/ValidatorList/ValidatorItem/Utils.tsx
+++ b/packages/app/src/library/ValidatorList/ValidatorItem/Utils.tsx
@@ -17,7 +17,7 @@ export const getIdentityDisplay = (
const superIdentity = _superIdentity?.identity ?? null;
const superRaw = _superIdentity?.superOf?.[1]?.Raw ?? null;
- const superDisplay = superIdentity?.info?.display?.Raw ?? null;
+ const superDisplay = superIdentity?.info?.display?.value?.asText() ?? null;
// check if super raw has been encoded
const superRawAsBytes = u8aToString(u8aUnwrapBytes(superRaw));
@@ -35,7 +35,7 @@ export const getIdentityDisplay = (
if (!foundSuper) {
// cehck sub identity exists, get display.Raw if it does
- const identity = _identity?.info?.display?.Raw ?? null;
+ const identity = _identity?.info?.display?.value?.asText() ?? null;
// check if identity has been byte encoded
const subIdentityAsBytes = u8aToString(u8aUnwrapBytes(identity));
diff --git a/packages/app/src/model/Query/IdentityOfMulti/index.ts b/packages/app/src/model/Query/IdentityOfMulti/index.ts
index d2c8dc5c5..19ea4332e 100644
--- a/packages/app/src/model/Query/IdentityOfMulti/index.ts
+++ b/packages/app/src/model/Query/IdentityOfMulti/index.ts
@@ -3,7 +3,6 @@
import type { PapiApi } from 'model/Api/types';
-// TODO: Hook up and test.
export class IdentityOfMulti {
#pApi: PapiApi;
diff --git a/packages/app/src/model/Query/SuperOfMulti/index.ts b/packages/app/src/model/Query/SuperOfMulti/index.ts
new file mode 100644
index 000000000..3ae9eb11c
--- /dev/null
+++ b/packages/app/src/model/Query/SuperOfMulti/index.ts
@@ -0,0 +1,28 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class SuperOfMulti {
+ #pApi: PapiApi;
+
+ #addresses: [string][];
+
+ constructor(pApi: PapiApi, addresses: [string][]) {
+ this.#pApi = pApi;
+ this.#addresses = addresses;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Identity.SuperOf.getValues(
+ this.#addresses
+ );
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return null;
+ }
+}
diff --git a/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts b/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
index 9f3410c3d..2283f4b86 100644
--- a/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
+++ b/packages/app/src/model/Subscribe/ActivePoolAccount/index.ts
@@ -6,6 +6,7 @@ import { defaultPoolNominations } from 'contexts/Pools/ActivePool/defaults';
import type { ActivePool, PoolRoles } from 'contexts/Pools/ActivePool/types';
import type { ActivePoolItem } from 'controllers/ActivePools/types';
import { ApiController } from 'controllers/Api';
+import { IdentitiesController } from 'controllers/Identities';
import type { Unsubscribable } from 'controllers/Subscriptions/types';
import type { PapiApi } from 'model/Api/types';
import { combineLatest, type Subscription } from 'rxjs';
@@ -106,11 +107,10 @@ export class ActivePoolAccount implements Unsubscribable {
if (peopleApi) {
// Fetch identities for roles and expand `bondedPool` state to store them.
- // TODO: IdentitiesController migrate to PapiApi.
- // bondedPool.roleIdentities = await IdentitiesController.fetch(
- // peopleApi,
- // this.getUniqueRoleAddresses(bondedPool.roles)
- // );
+ bondedPool.roleIdentities = await IdentitiesController.fetch(
+ peopleApi,
+ this.getUniqueRoleAddresses(bondedPool.roles)
+ );
}
const bondedPoolFormatted = {
From e6446ffb2a5031967e3a2be4a4311cddb81bc2b5 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 21:12:15 +0700
Subject: [PATCH 48/84] migrate validator entries queries
---
.../Validators/ValidatorEntries/index.tsx | 36 ++++++++++++-------
.../model/Query/SessionValidators/index.ts | 23 ++++++++++++
.../src/model/Query/ValidatorsMulti/index.ts | 28 +++++++++++++++
3 files changed, 74 insertions(+), 13 deletions(-)
create mode 100644 packages/app/src/model/Query/SessionValidators/index.ts
create mode 100644 packages/app/src/model/Query/ValidatorsMulti/index.ts
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index 57e4dd0a1..f133ae9eb 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -36,6 +36,8 @@ import type { AnyJson, Sync } from '@w3ux/types';
import { Validators } from 'model/Entries/Validators';
import { ApiController } from 'controllers/Api';
import { perbillToPercent } from 'library/Utils';
+import { SessionValidators } from 'model/Query/SessionValidators';
+import { ValidatorsMulti } from 'model/Query/ValidatorsMulti';
export const ValidatorsContext = createContext(
defaultValidatorsContext
@@ -340,11 +342,11 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// Subscribe to active session validators.
const fetchSessionValidators = async () => {
- if (!api || !isReady) {
+ if (!isReady) {
return;
}
- const sessionValidatorsRaw: AnyApi = await api.query.session.validators();
- setSessionValidators(sessionValidatorsRaw.toHuman());
+ const { pApi } = ApiController.get(network);
+ setSessionValidators(await new SessionValidators(pApi).fetch());
};
// Subscribe to active parachain validators.
@@ -368,21 +370,29 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
}
const v: string[] = [];
+ const vMulti: [string][] = [];
for (const { address } of addresses) {
v.push(address);
+ vMulti.push([address]);
}
- const results = await api.query.staking.validators.multi(v);
+
+ const { pApi } = ApiController.get(network);
+ const resultsMulti =
+ (await new ValidatorsMulti(pApi, vMulti).fetch()) || [];
const formatted: Validator[] = [];
- for (let i = 0; i < results.length; i++) {
- const prefs: AnyApi = results[i].toHuman();
- formatted.push({
- address: v[i],
- prefs: {
- commission: prefs?.commission.replace(/%/g, '') ?? '0',
- blocked: prefs.blocked,
- },
- });
+ for (let i = 0; i < resultsMulti.length; i++) {
+ const prefs: AnyApi = resultsMulti[i];
+
+ if (prefs) {
+ formatted.push({
+ address: v[i],
+ prefs: {
+ commission: Number(perbillToPercent(prefs.commission).toString()),
+ blocked: prefs.blocked,
+ },
+ });
+ }
}
return formatted;
};
diff --git a/packages/app/src/model/Query/SessionValidators/index.ts b/packages/app/src/model/Query/SessionValidators/index.ts
new file mode 100644
index 000000000..6b35d998c
--- /dev/null
+++ b/packages/app/src/model/Query/SessionValidators/index.ts
@@ -0,0 +1,23 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class SessionValidators {
+ #pApi: PapiApi;
+
+ constructor(pApi: PapiApi) {
+ this.#pApi = pApi;
+ }
+
+ // Fetch network constants.
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Session.Validators.getValue();
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+ return [];
+ }
+}
diff --git a/packages/app/src/model/Query/ValidatorsMulti/index.ts b/packages/app/src/model/Query/ValidatorsMulti/index.ts
new file mode 100644
index 000000000..66c17bc8d
--- /dev/null
+++ b/packages/app/src/model/Query/ValidatorsMulti/index.ts
@@ -0,0 +1,28 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ValidatorsMulti {
+ #pApi: PapiApi;
+
+ #addresses: [string][];
+
+ constructor(pApi: PapiApi, addresses: [string][]) {
+ this.#pApi = pApi;
+ this.#addresses = addresses;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Staking.Validators.getValues(
+ this.#addresses
+ );
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return null;
+ }
+}
From 69e34a0749d5615d251a8f5f984a58edb5d6f2cf Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Mon, 18 Nov 2024 21:56:11 +0700
Subject: [PATCH 49/84] add `ParaSessionAccounts` query
---
.../Validators/ValidatorEntries/index.tsx | 35 ++++++-------------
packages/app/src/model/Query/Era/index.ts | 1 -
.../model/Query/ParaSessionAccounts/index.ts | 29 +++++++++++++++
3 files changed, 40 insertions(+), 25 deletions(-)
create mode 100644 packages/app/src/model/Query/ParaSessionAccounts/index.ts
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index f133ae9eb..bf007d6f8 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -4,8 +4,8 @@
import { rmCommas, shuffle } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
-import { createContext, useContext, useEffect, useRef, useState } from 'react';
-import type { AnyApi, Fn, SystemChainId } from 'types';
+import { createContext, useContext, useEffect, useState } from 'react';
+import type { AnyApi, SystemChainId } from 'types';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import { useNetwork } from 'contexts/Network';
import { useApi } from 'contexts/Api';
@@ -38,6 +38,7 @@ import { ApiController } from 'controllers/Api';
import { perbillToPercent } from 'library/Utils';
import { SessionValidators } from 'model/Query/SessionValidators';
import { ValidatorsMulti } from 'model/Query/ValidatorsMulti';
+import { ParaSessionAccounts } from 'model/Query/ParaSessionAccounts';
export const ValidatorsContext = createContext(
defaultValidatorsContext
@@ -83,9 +84,6 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
[]
);
- // Stores unsub object for para session.
- const sessionParaUnsub = useRef();
-
// Stores the average network commission rate.
const [avgCommission, setAvgCommission] = useState(0);
@@ -350,16 +348,13 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
};
// Subscribe to active parachain validators.
- const subscribeParachainValidators = async () => {
- if (!api || !isReady) {
- return;
- }
- const unsub: AnyApi = await api.query.paraSessionInfo.accountKeys(
- earliestStoredSession.toString(),
- (v: AnyApi) => {
- setSessionParaValidators(v.toHuman());
- sessionParaUnsub.current = unsub;
- }
+ const getParachainValidators = async () => {
+ const { pApi } = ApiController.get(network);
+ setSessionParaValidators(
+ await new ParaSessionAccounts(
+ pApi,
+ earliestStoredSession.toString()
+ ).fetch()
);
};
@@ -591,18 +586,10 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// Fetch parachain session validators when `earliestStoredSession` ready.
useEffectIgnoreInitial(() => {
if (isReady && earliestStoredSession.isGreaterThan(0)) {
- subscribeParachainValidators();
+ getParachainValidators();
}
}, [isReady, earliestStoredSession]);
- // Unsubscribe on network change and component unmount.
- useEffect(() => {
- sessionParaUnsub.current?.();
- return () => {
- sessionParaUnsub.current?.();
- };
- }, [network]);
-
return (
Date: Tue, 19 Nov 2024 11:22:12 +0700
Subject: [PATCH 50/84] add `PoolMemberBatchEvent` and migrate pool member
batches
---
.../src/contexts/Pools/PoolMembers/index.tsx | 105 ++++++++----------
.../src/controllers/Subscriptions/types.ts | 2 +
.../model/Subscribe/PoolMembersMulti/index.ts | 82 ++++++++++++++
.../model/Subscribe/PoolMembersMulti/types.ts | 15 +++
packages/app/src/types.ts | 2 +
5 files changed, 146 insertions(+), 60 deletions(-)
create mode 100644 packages/app/src/model/Subscribe/PoolMembersMulti/index.ts
create mode 100644 packages/app/src/model/Subscribe/PoolMembersMulti/types.ts
diff --git a/packages/app/src/contexts/Pools/PoolMembers/index.tsx b/packages/app/src/contexts/Pools/PoolMembers/index.tsx
index 02cf7dcdd..87ffa61dc 100644
--- a/packages/app/src/contexts/Pools/PoolMembers/index.tsx
+++ b/packages/app/src/contexts/Pools/PoolMembers/index.tsx
@@ -5,7 +5,7 @@ import { setStateWithRef } from '@w3ux/utils';
import type { ReactNode } from 'react';
import { createContext, useContext, useRef, useState } from 'react';
import { usePlugins } from 'contexts/Plugins';
-import type { AnyApi, AnyMetaBatch, Fn, MaybeAddress } from 'types';
+import type { AnyMetaBatch, MaybeAddress } from 'types';
import { useEffectIgnoreInitial } from '@w3ux/hooks';
import { useNetwork } from 'contexts/Network';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
@@ -13,6 +13,10 @@ import { useApi } from '../../Api';
import { defaultPoolMembers } from './defaults';
import type { PoolMember, PoolMemberContext } from './types';
import type { Sync } from '@w3ux/types';
+import { PoolMembersMulti } from 'model/Subscribe/PoolMembersMulti';
+import { SubscriptionsController } from 'controllers/Subscriptions';
+import { useEventListener } from 'usehooks-ts';
+import { isCustomEvent } from 'controllers/utils';
export const PoolMembersContext =
createContext(defaultPoolMembers);
@@ -20,8 +24,8 @@ export const PoolMembersContext =
export const usePoolMembers = () => useContext(PoolMembersContext);
export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
+ const { isReady } = useApi();
const { network } = useNetwork();
- const { api, isReady } = useApi();
const { pluginEnabled } = usePlugins();
const { activeAccount } = useActiveAccounts();
@@ -36,8 +40,8 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
useState({});
const poolMembersMetaBatchesRef = useRef(poolMembersMetaBatches);
- // Stores the meta batch subscriptions for pool lists.
- const poolMembersSubs = useRef>({});
+ // Stores the meta batch subscription keys for pool lists.
+ const poolMembersSubs = useRef([]);
// Update poolMembersApi fetched status.
const setFetchedPoolMembersApi = (status: Sync) => {
@@ -72,32 +76,18 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
};
const unsubscribeAndResetMeta = () => {
- Object.values(poolMembersSubs.current).map((batch: Fn[]) =>
- Object.entries(batch).map(([, v]) => v())
+ Object.values(poolMembersSubs.current).map((key: string) =>
+ SubscriptionsController.remove(network, `poolMembersBatch-${key}`)
);
setStateWithRef({}, setPoolMembersMetaBatch, poolMembersMetaBatchesRef);
};
- /*
- Fetches a new batch of pool member metadata.
- structure:
- {
- key: {
- [
- {
- identities: [],
- super_identities: [],
- }
- ]
- },
- };
- */
const fetchPoolMembersMetaBatch = async (
key: string,
p: AnyMetaBatch,
refetch = false
) => {
- if (!isReady || !api) {
+ if (!isReady) {
return;
}
if (!p.length) {
@@ -120,15 +110,16 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
poolMembersMetaBatchesRef
);
- if (poolMembersSubs.current[key] !== undefined) {
- for (const unsub of poolMembersSubs.current[key]) {
- unsub();
- }
+ if (key in poolMembersSubs.current) {
+ SubscriptionsController.remove(network, `poolMembersBatch-${key}`);
+ poolMembersSubs.current = poolMembersSubs.current.filter(
+ (item) => item !== key
+ );
}
}
// aggregate member addresses
- const addresses = [];
+ const addresses: string[] = [];
for (const { who } of p) {
addresses.push(who);
}
@@ -143,32 +134,15 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
poolMembersMetaBatchesRef
);
- const subscribeToPoolMembers = async (addr: string[]) => {
- const unsub = await api.query.nominationPools.poolMembers.multi(
- addr,
- (_pools) => {
- const pools = [];
- for (const _pool of _pools) {
- pools.push(_pool.toHuman());
- }
- const updated = Object.assign(poolMembersMetaBatchesRef.current);
- updated[key].poolMembers = pools;
- setStateWithRef(
- { ...updated },
- setPoolMembersMetaBatch,
- poolMembersMetaBatchesRef
- );
- }
- );
- return unsub;
- };
-
- // initiate subscriptions
- await Promise.all([subscribeToPoolMembers(addresses)]).then(
- (unsubs: Fn[]) => {
- addMetaBatchUnsubs(key, unsubs);
- }
+ // initialise subscription
+ SubscriptionsController.set(
+ network,
+ `poolMembersBatch-${key}`,
+ new PoolMembersMulti(network, key, addresses)
);
+
+ // Record key.
+ poolMembersSubs.current.push(key);
};
// Removes a member from the member list and updates state. Requires subscan to be enabled.
@@ -178,17 +152,28 @@ export const PoolMembersProvider = ({ children }: { children: ReactNode }) => {
}
};
- /*
- * Helper: to add mataBatch unsubs by key.
- */
- const addMetaBatchUnsubs = (key: string, unsubs: Fn[]) => {
- const subs = poolMembersSubs.current;
- const sub = subs[key] ?? [];
- sub.push(...unsubs);
- subs[key] = sub;
- poolMembersSubs.current = subs;
+ // Handle new pool members batch event.
+ const handleNewPoolMembersBatch = (e: Event) => {
+ if (isCustomEvent(e)) {
+ const { key, poolMembers } = e.detail;
+
+ const updated = Object.assign(poolMembersMetaBatchesRef.current);
+ updated[key].poolMembers = poolMembers;
+ setStateWithRef(
+ { ...updated },
+ setPoolMembersMetaBatch,
+ poolMembersMetaBatchesRef
+ );
+ }
};
+ const documentRef = useRef(document);
+ useEventListener(
+ 'new-pool-members-batch',
+ handleNewPoolMembersBatch,
+ documentRef
+ );
+
return (
=> {
+ try {
+ const { pApi } = ApiController.get(this.#network);
+ if (pApi && this.#sub === undefined) {
+ const bestOrFinalized = 'best';
+
+ const sub = combineLatest(
+ this.#addresses.map((address) =>
+ pApi.query.NominationPools.PoolMembers.watchValue(
+ address,
+ bestOrFinalized
+ )
+ )
+ ).subscribe((results) => {
+ const formatted = results.map((result) => ({
+ lastRecordedRewardCounter:
+ result.last_recorded_reward_counter.toString(),
+ points: result.points.toString(),
+ poolId: result.pool_id.toString(),
+ unbondingEras: Object.fromEntries(
+ result.unbonding_eras.map(([key, value]: [number, bigint]) => [
+ key.toString(),
+ value.toString(),
+ ])
+ ),
+ }));
+
+ const detail: PoolMemberBatchEvent = {
+ key: this.#key,
+ addresses: this.#addresses,
+ poolMembers: formatted,
+ };
+
+ document.dispatchEvent(
+ new CustomEvent('new-pool-members-batch', {
+ detail,
+ })
+ );
+ });
+
+ this.#sub = sub;
+ }
+ } catch (e) {
+ // Subscription failed.
+ }
+ };
+
+ // Unsubscribe from class subscription.
+ unsubscribe = (): void => {
+ if (typeof this.#sub?.unsubscribe === 'function') {
+ this.#sub.unsubscribe();
+ }
+ };
+}
diff --git a/packages/app/src/model/Subscribe/PoolMembersMulti/types.ts b/packages/app/src/model/Subscribe/PoolMembersMulti/types.ts
new file mode 100644
index 000000000..ed7b85514
--- /dev/null
+++ b/packages/app/src/model/Subscribe/PoolMembersMulti/types.ts
@@ -0,0 +1,15 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+export interface PoolMemberBatchEvent {
+ key: string;
+ addresses: string[];
+ poolMembers: Record<
+ number,
+ {
+ poolId: string;
+ points: string;
+ unbondingEras: Record;
+ }
+ >;
+}
diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts
index 22ae59ee6..3c4c47edc 100644
--- a/packages/app/src/types.ts
+++ b/packages/app/src/types.ts
@@ -24,6 +24,7 @@ import type { BondedAccount } from 'contexts/Bonded/types';
import type { FastUnstakeConfigResult } from 'model/Subscribe/FastUnstakeConfig/types';
import type { FastUnstakeQueueResult } from 'contexts/FastUnstake/types';
import type { AccountProxiesEvent } from 'model/Subscribe/AccountProxies/types';
+import type { PoolMemberBatchEvent } from 'model/Subscribe/PoolMembersMulti/types';
declare global {
interface Window {
@@ -46,6 +47,7 @@ declare global {
stakingMetrics: APIStakingMetrics;
}>;
'new-active-pool': CustomEvent;
+ 'new-pool-members-batch': CustomEvent;
'new-fast-unstake-config': CustomEvent;
'new-fast-unstake-deposit': CustomEvent;
'new-account-proxies': CustomEvent;
From 6209042d259c68a9d336359347061fbe14f78e93 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Tue, 19 Nov 2024 11:43:12 +0700
Subject: [PATCH 51/84] migrate `ValidatorEntries` multi queries
---
.../Validators/ValidatorEntries/index.tsx | 40 ++++++++++---------
.../Query/ErasRewardPointsMulti/index.ts | 28 +++++++++++++
.../Query/ErasValidatorRewardMulti/index.ts | 29 ++++++++++++++
3 files changed, 79 insertions(+), 18 deletions(-)
create mode 100644 packages/app/src/model/Query/ErasRewardPointsMulti/index.ts
create mode 100644 packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index bf007d6f8..e3aea5fdd 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -1,7 +1,7 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { rmCommas, shuffle } from '@w3ux/utils';
+import { shuffle } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import type { ReactNode } from 'react';
import { createContext, useContext, useEffect, useState } from 'react';
@@ -39,6 +39,8 @@ import { perbillToPercent } from 'library/Utils';
import { SessionValidators } from 'model/Query/SessionValidators';
import { ValidatorsMulti } from 'model/Query/ValidatorsMulti';
import { ParaSessionAccounts } from 'model/Query/ParaSessionAccounts';
+import { ErasRewardPointsMulti } from 'model/Query/ErasRewardPointsMulti';
+import { ErasValidatorReward } from 'model/Query/ErasValidatorRewardMulti';
export const ValidatorsContext = createContext(
defaultValidatorsContext
@@ -50,7 +52,6 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
const {
isReady,
- api,
peopleApi,
peopleApiStatus,
consts: { historyDepth },
@@ -118,11 +119,11 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
}
return {
- total: rmCommas(result.total),
+ total: result.total.toString(),
individual: Object.fromEntries(
- Object.entries(result.individual).map(([key, value]) => [
+ result.individual.map(([key, value]: [number, string]) => [
key,
- rmCommas(value as string),
+ (value as string).toString(),
])
),
};
@@ -148,9 +149,10 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// Fetches era reward points for eligible eras.
const fetchErasRewardPoints = async () => {
+ const { pApi } = ApiController.get(network);
if (
activeEra.index.isZero() ||
- !api ||
+ !pApi ||
erasRewardPointsFetched !== 'unsynced'
) {
return;
@@ -170,12 +172,9 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
let erasProcessed = new BigNumber(0);
// Iterate eras and process reward points.
- const calls = [];
const eras = [];
do {
- calls.push(api.query.staking.erasRewardPoints(currentEra.toString()));
eras.push(currentEra);
-
currentEra = currentEra.minus(1);
erasProcessed = erasProcessed.plus(1);
} while (
@@ -183,11 +182,14 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
erasProcessed.isLessThan(totalEras)
);
+ const erasMulti: [string][] = eras.map((e) => [e.toString()]);
+ const results = await new ErasRewardPointsMulti(pApi, erasMulti).fetch();
+
// Make calls and format reward point results.
const newErasRewardPoints: ErasRewardPoints = {};
let i = 0;
- for (const result of await Promise.all(calls)) {
- const formatted = processEraRewardPoints(result.toHuman(), eras[i]);
+ for (const result of results) {
+ const formatted = processEraRewardPoints(result, eras[i]);
if (formatted) {
newErasRewardPoints[eras[i].toString()] = formatted;
}
@@ -279,7 +281,7 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// Fetches and formats the active validator set, and derives metrics from the result.
const fetchValidators = async () => {
- if (!isReady || !api || validatorsFetched !== 'unsynced') {
+ if (!isReady || validatorsFetched !== 'unsynced') {
return;
}
setValidatorsFetched('syncing');
@@ -360,7 +362,7 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// Fetches prefs for a list of validators.
const fetchValidatorPrefs = async (addresses: ValidatorAddresses) => {
- if (!addresses.length || !api) {
+ if (!addresses.length) {
return null;
}
@@ -485,7 +487,9 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
// Gets average validator reward for provided number of days.
const getAverageEraValidatorReward = async () => {
- if (!api || !isReady || activeEra.index.isZero()) {
+ const { pApi } = ApiController.get(network);
+
+ if (!pApi || !isReady || activeEra.index.isZero()) {
setAverageEraValidatorReward({
days: 0,
reward: new BigNumber(0),
@@ -510,12 +514,12 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
thisEra = thisEra.minus(1);
} while (thisEra.gte(endEra));
- const validatorEraRewards =
- await api.query.staking.erasValidatorReward.multi(eras);
+ const erasMulti: [string][] = eras.map((e) => [e.toString()]);
+ const results = await new ErasValidatorReward(pApi, erasMulti).fetch();
- const reward = validatorEraRewards
+ const reward = results
.map((v) => {
- const value = new BigNumber(v.toString() === '' ? 0 : v.toString());
+ const value = new BigNumber(!v ? 0 : v.toString());
if (value.isNaN()) {
return new BigNumber(0);
}
diff --git a/packages/app/src/model/Query/ErasRewardPointsMulti/index.ts b/packages/app/src/model/Query/ErasRewardPointsMulti/index.ts
new file mode 100644
index 000000000..14ac6a518
--- /dev/null
+++ b/packages/app/src/model/Query/ErasRewardPointsMulti/index.ts
@@ -0,0 +1,28 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ErasRewardPointsMulti {
+ #pApi: PapiApi;
+
+ #eras: [string][];
+
+ constructor(pApi: PapiApi, eras: [string][]) {
+ this.#pApi = pApi;
+ this.#eras = eras;
+ }
+
+ async fetch() {
+ try {
+ const results = await this.#pApi.query.Staking.ErasRewardPoints.getValues(
+ this.#eras
+ );
+ return results;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return [];
+ }
+}
diff --git a/packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts b/packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts
new file mode 100644
index 000000000..61894f746
--- /dev/null
+++ b/packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts
@@ -0,0 +1,29 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ErasValidatorReward {
+ #pApi: PapiApi;
+
+ #eras: [string][];
+
+ constructor(pApi: PapiApi, eras: [string][]) {
+ this.#pApi = pApi;
+ this.#eras = eras;
+ }
+
+ async fetch() {
+ try {
+ const results =
+ await this.#pApi.query.Staking.ErasValidatorReward.getValues(
+ this.#eras
+ );
+ return results;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return [];
+ }
+}
From 116be101459f4a0cce304d308749073b39ec0d6d Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Tue, 19 Nov 2024 12:07:44 +0700
Subject: [PATCH 52/84] migrate `ClaimedRewards`, `BondedMulti` queries
---
packages/app/src/contexts/Payouts/index.tsx | 22 +++++++++----
.../app/src/model/Query/BondedMulti/index.ts | 28 ++++++++++++++++
.../src/model/Query/ClaimedRewards/index.ts | 32 +++++++++++++++++++
3 files changed, 75 insertions(+), 7 deletions(-)
create mode 100644 packages/app/src/model/Query/BondedMulti/index.ts
create mode 100644 packages/app/src/model/Query/ClaimedRewards/index.ts
diff --git a/packages/app/src/contexts/Payouts/index.tsx b/packages/app/src/contexts/Payouts/index.tsx
index 5ef3138f6..31e5b57cf 100644
--- a/packages/app/src/contexts/Payouts/index.tsx
+++ b/packages/app/src/contexts/Payouts/index.tsx
@@ -24,6 +24,9 @@ import {
setLocalEraExposure,
setLocalUnclaimedPayouts,
} from './Utils';
+import { BondedMulti } from 'model/Query/BondedMulti';
+import { ApiController } from 'controllers/Api';
+import { ClaimedRewards } from 'model/Query/ClaimedRewards';
const worker = new Worker();
@@ -136,6 +139,7 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
// Start pending payout process once exposure data is fetched.
const getUnclaimedPayouts = async () => {
+ const { pApi } = ApiController.get(network);
if (!api || !activeAccount) {
return;
}
@@ -163,11 +167,15 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
);
// Fetch controllers in order to query ledgers.
- const bondedResults =
- await api.query.staking.bonded.multi(uniqueValidators);
+ const uniqueValidatorsMulti: [string][] = uniqueValidators.map((v) => [v]);
+ const bondedResultsMulti = await new BondedMulti(
+ pApi,
+ uniqueValidatorsMulti
+ ).fetch();
+
const validatorControllers: Record = {};
- for (let i = 0; i < bondedResults.length; i++) {
- const ctlr = bondedResults[i].unwrapOr(null);
+ for (let i = 0; i < bondedResultsMulti.length; i++) {
+ const ctlr = bondedResultsMulti[i] || null;
if (ctlr) {
validatorControllers[uniqueValidators[i]] = ctlr;
}
@@ -186,18 +194,18 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
const results = await Promise.all(
unclaimedRewardsEntries.map(([era, v]) =>
- api.query.staking.claimedRewards(era, v)
+ new ClaimedRewards(pApi, era, v).fetch()
)
);
for (let i = 0; i < results.length; i++) {
- const pages = results[i].toHuman() || [];
+ const pages = results[i] || [];
const era = unclaimedRewardsEntries[i][0];
const validator = unclaimedRewardsEntries[i][1];
const exposure = getLocalEraExposure(network, era, activeAccount);
const exposedPage =
exposure?.[validator]?.exposedPage !== undefined
- ? String(exposure[validator].exposedPage)
+ ? Number(exposure[validator].exposedPage)
: undefined;
// Add to `unclaimedRewards` if payout page has not yet been claimed.
diff --git a/packages/app/src/model/Query/BondedMulti/index.ts b/packages/app/src/model/Query/BondedMulti/index.ts
new file mode 100644
index 000000000..d56d994d9
--- /dev/null
+++ b/packages/app/src/model/Query/BondedMulti/index.ts
@@ -0,0 +1,28 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class BondedMulti {
+ #pApi: PapiApi;
+
+ #addresses: [string][];
+
+ constructor(pApi: PapiApi, eras: [string][]) {
+ this.#pApi = pApi;
+ this.#addresses = eras;
+ }
+
+ async fetch() {
+ try {
+ const results = await this.#pApi.query.Staking.Bonded.getValues(
+ this.#addresses
+ );
+ return results;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return [];
+ }
+}
diff --git a/packages/app/src/model/Query/ClaimedRewards/index.ts b/packages/app/src/model/Query/ClaimedRewards/index.ts
new file mode 100644
index 000000000..35a90cfdf
--- /dev/null
+++ b/packages/app/src/model/Query/ClaimedRewards/index.ts
@@ -0,0 +1,32 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ClaimedRewards {
+ #pApi: PapiApi;
+
+ #era: string;
+
+ #address: string;
+
+ constructor(pApi: PapiApi, era: string, address: string) {
+ this.#pApi = pApi;
+ this.#era = era;
+ this.#address = address;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Staking.ClaimedRewards.getValue(
+ this.#era,
+ this.#address
+ );
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return undefined;
+ }
+}
From acab254e3a6a22d2271e26a9b9acdf3cf1a7c7c0 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Tue, 19 Nov 2024 12:21:54 +0700
Subject: [PATCH 53/84] migrate `Payouts` queries
---
packages/app/src/contexts/Payouts/index.tsx | 35 ++++++++++++-------
.../src/model/Query/ErasRewardPoints/index.ts | 28 +++++++++++++++
.../model/Query/ErasValidatorReward/index.ts | 27 ++++++++++++++
.../src/model/Query/ValidatorPrefs/index.ts | 32 +++++++++++++++++
4 files changed, 110 insertions(+), 12 deletions(-)
create mode 100644 packages/app/src/model/Query/ErasRewardPoints/index.ts
create mode 100644 packages/app/src/model/Query/ErasValidatorReward/index.ts
create mode 100644 packages/app/src/model/Query/ValidatorPrefs/index.ts
diff --git a/packages/app/src/contexts/Payouts/index.tsx b/packages/app/src/contexts/Payouts/index.tsx
index 31e5b57cf..e8cd04819 100644
--- a/packages/app/src/contexts/Payouts/index.tsx
+++ b/packages/app/src/contexts/Payouts/index.tsx
@@ -8,7 +8,7 @@ import { useApi } from 'contexts/Api';
import type { AnyApi } from 'types';
import type { AnyJson, Sync } from '@w3ux/types';
import Worker from 'workers/stakers?worker';
-import { rmCommas, setStateWithRef } from '@w3ux/utils';
+import { setStateWithRef } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import { useNetwork } from 'contexts/Network';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
@@ -27,6 +27,10 @@ import {
import { BondedMulti } from 'model/Query/BondedMulti';
import { ApiController } from 'controllers/Api';
import { ClaimedRewards } from 'model/Query/ClaimedRewards';
+import { ErasValidatorReward } from 'model/Query/ErasValidatorReward';
+import { ErasRewardPoints } from 'model/Query/ErasRewardPoints';
+import { ValidatorPrefs } from 'model/Query/ValidatorPrefs';
+import { perbillToPercent } from 'library/Utils';
const worker = new Worker();
@@ -238,10 +242,10 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
if (validators.length > 0) {
calls.push(
Promise.all([
- api.query.staking.erasValidatorReward(era),
- api.query.staking.erasRewardPoints(era),
+ new ErasValidatorReward(pApi, era).fetch(),
+ new ErasRewardPoints(pApi, era).fetch(),
...validators.map((validator: AnyJson) =>
- api.query.staking.erasValidatorPrefs(era, validator)
+ new ValidatorPrefs(pApi, era, validator).fetch()
),
])
);
@@ -252,18 +256,22 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
// `unclaimed`: Record>.
const unclaimed: UnclaimedPayouts = {};
let i = 0;
- for (const [reward, points, ...prefs] of await Promise.all(calls)) {
+ for (const [reward, eraRewardPoints, ...prefs] of await Promise.all(
+ calls
+ )) {
const era = Object.keys(unclaimedByEra)[i];
- const eraTotalPayout = new BigNumber(rmCommas(reward.toHuman()));
- const eraRewardPoints = points.toHuman();
+ const eraTotalPayout = new BigNumber(reward.toString());
const unclaimedValidators = unclaimedByEra[era];
let j = 0;
for (const pref of prefs) {
- const eraValidatorPrefs = pref.toHuman();
+ const eraValidatorPrefs = {
+ commission: pref.commission,
+ blocked: pref.blocked,
+ };
const commission = new BigNumber(
- eraValidatorPrefs.commission.replace(/%/g, '')
- ).multipliedBy(0.01);
+ perbillToPercent(eraValidatorPrefs.commission)
+ );
// Get validator from era exposure data. Falls back no null if it cannot be found.
const validator = unclaimedValidators?.[j] || '';
@@ -281,11 +289,14 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
// Calculate the validator's share of total era payout.
const totalRewardPoints = new BigNumber(
- rmCommas(eraRewardPoints.total)
+ eraRewardPoints.total.toString()
);
const validatorRewardPoints = new BigNumber(
- rmCommas(eraRewardPoints.individual?.[validator] || '0')
+ eraRewardPoints.individual.find(
+ ([v]: [string]) => v === validator
+ )?.[1] || '0'
);
+
const avail = eraTotalPayout
.multipliedBy(validatorRewardPoints)
.dividedBy(totalRewardPoints);
diff --git a/packages/app/src/model/Query/ErasRewardPoints/index.ts b/packages/app/src/model/Query/ErasRewardPoints/index.ts
new file mode 100644
index 000000000..149910abb
--- /dev/null
+++ b/packages/app/src/model/Query/ErasRewardPoints/index.ts
@@ -0,0 +1,28 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ErasRewardPoints {
+ #pApi: PapiApi;
+
+ #era: string;
+
+ constructor(pApi: PapiApi, era: string) {
+ this.#pApi = pApi;
+ this.#era = era;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Staking.ErasRewardPoints.getValue(
+ this.#era
+ );
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return [];
+ }
+}
diff --git a/packages/app/src/model/Query/ErasValidatorReward/index.ts b/packages/app/src/model/Query/ErasValidatorReward/index.ts
new file mode 100644
index 000000000..fc6a9b9bf
--- /dev/null
+++ b/packages/app/src/model/Query/ErasValidatorReward/index.ts
@@ -0,0 +1,27 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ErasValidatorReward {
+ #pApi: PapiApi;
+
+ #era: string;
+
+ constructor(pApi: PapiApi, era: string) {
+ this.#pApi = pApi;
+ this.#era = era;
+ }
+
+ async fetch() {
+ try {
+ const result =
+ await this.#pApi.query.Staking.ErasValidatorReward.getValue(this.#era);
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return [];
+ }
+}
diff --git a/packages/app/src/model/Query/ValidatorPrefs/index.ts b/packages/app/src/model/Query/ValidatorPrefs/index.ts
new file mode 100644
index 000000000..9554a8246
--- /dev/null
+++ b/packages/app/src/model/Query/ValidatorPrefs/index.ts
@@ -0,0 +1,32 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { PapiApi } from 'model/Api/types';
+
+export class ValidatorPrefs {
+ #pApi: PapiApi;
+
+ #era: string;
+
+ #address: string;
+
+ constructor(pApi: PapiApi, era: string, address: string) {
+ this.#pApi = pApi;
+ this.#era = era;
+ this.#address = address;
+ }
+
+ async fetch() {
+ try {
+ const result = await this.#pApi.query.Staking.ErasValidatorPrefs.getValue(
+ this.#era,
+ this.#address
+ );
+ return result;
+ } catch (e) {
+ // Silently fail.
+ }
+
+ return undefined;
+ }
+}
From d60e7848ddd5a76cf634f22525db19d55b9ebb3f Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Tue, 19 Nov 2024 14:55:29 +0700
Subject: [PATCH 54/84] fixes
---
packages/app/src/contexts/Payouts/index.tsx | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/packages/app/src/contexts/Payouts/index.tsx b/packages/app/src/contexts/Payouts/index.tsx
index e8cd04819..a61013bca 100644
--- a/packages/app/src/contexts/Payouts/index.tsx
+++ b/packages/app/src/contexts/Payouts/index.tsx
@@ -42,7 +42,7 @@ export const usePayouts = () => useContext(PayoutsContext);
export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
- const { api, consts, activeEra } = useApi();
+ const { consts, activeEra } = useApi();
const { activeAccount } = useActiveAccounts();
const { isNominating, fetchEraStakers } = useStaking();
const { maxExposurePageSize } = consts;
@@ -144,7 +144,7 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
// Start pending payout process once exposure data is fetched.
const getUnclaimedPayouts = async () => {
const { pApi } = ApiController.get(network);
- if (!api || !activeAccount) {
+ if (!pApi || !activeAccount) {
return;
}
@@ -301,7 +301,7 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
.multipliedBy(validatorRewardPoints)
.dividedBy(totalRewardPoints);
- const valCut = commission.multipliedBy(avail);
+ const valCut = commission.multipliedBy(0.01).multipliedBy(avail);
const unclaimedPayout = total.isZero()
? new BigNumber(0)
@@ -309,7 +309,8 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
.minus(valCut)
.multipliedBy(staked)
.dividedBy(total)
- .plus(isValidator ? valCut : 0);
+ .plus(isValidator ? valCut : 0)
+ .integerValue(BigNumber.ROUND_DOWN);
if (!unclaimedPayout.isZero()) {
unclaimed[era] = {
From ae8772e0093cf16405e05297d47571cdb7692b2b Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Wed, 20 Nov 2024 17:05:17 +0700
Subject: [PATCH 55/84] fix
---
packages/app/src/hooks/useActiveBalances/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/app/src/hooks/useActiveBalances/index.tsx b/packages/app/src/hooks/useActiveBalances/index.tsx
index 491bfe47c..0b5c91afc 100644
--- a/packages/app/src/hooks/useActiveBalances/index.tsx
+++ b/packages/app/src/hooks/useActiveBalances/index.tsx
@@ -62,7 +62,7 @@ export const useActiveBalances = ({
// Gets an active balance's locks.
const getLocks = (address: MaybeAddress): BalanceLocks => {
if (address) {
- const maybeLocks = activeBalances[address]?.balances.locks;
+ const maybeLocks = activeBalances[address]?.balances?.locks;
if (maybeLocks) {
return { locks: maybeLocks, maxLock: getMaxLock(maybeLocks) };
}
From 3bbc829690093333e0b62f614142d9b3111b3263 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Wed, 20 Nov 2024 17:13:28 +0700
Subject: [PATCH 56/84] fix
---
packages/app/src/hooks/useActiveBalances/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/app/src/hooks/useActiveBalances/index.tsx b/packages/app/src/hooks/useActiveBalances/index.tsx
index 0b5c91afc..341e10cca 100644
--- a/packages/app/src/hooks/useActiveBalances/index.tsx
+++ b/packages/app/src/hooks/useActiveBalances/index.tsx
@@ -43,7 +43,7 @@ export const useActiveBalances = ({
// Gets an active balance's balance.
const getBalance = (address: MaybeAddress) => {
if (address) {
- const maybeBalance = activeBalances[address]?.balances.balance;
+ const maybeBalance = activeBalances[address]?.balances?.balance;
if (maybeBalance) {
return maybeBalance;
}
From 77fe892ae0de709faba08fa05464f2b95f355a9d Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Wed, 20 Nov 2024 20:38:29 +0700
Subject: [PATCH 57/84] prepare tx hooks
---
packages/app/package.json | 6 +-
.../app/src/hooks/useBatchCallPapi/index.tsx | 49 ++
.../src/hooks/useBondGreatestFee/index.tsx | 26 +-
.../src/hooks/useProxySupportedPapi/index.tsx | 66 +++
.../hooks/useSubmitExtrinsicPapi/index.tsx | 281 +++++++++
.../src/hooks/useSubmitExtrinsicPapi/types.ts | 24 +
yarn.lock | 539 +++++++-----------
7 files changed, 655 insertions(+), 336 deletions(-)
create mode 100644 packages/app/src/hooks/useBatchCallPapi/index.tsx
create mode 100644 packages/app/src/hooks/useProxySupportedPapi/index.tsx
create mode 100644 packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx
create mode 100644 packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts
diff --git a/packages/app/package.json b/packages/app/package.json
index 948933807..2e68e823b 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -24,14 +24,16 @@
"@fortawesome/react-fontawesome": "^0.2.2",
"@ledgerhq/hw-transport-webhid": "^6.29.2",
"@polkadot-api/merkleize-metadata": "^1.1.4",
+ "@polkadot-api/signers-common": "^0.1.1",
+ "@polkadot-api/substrate-bindings": "^0.9.3",
"@polkadot/api": "^14.3.1",
"@polkadot/rpc-provider": "^14.3.1",
"@polkawatch/ddp-client": "^2.0.20",
"@substrate/connect": "^2.0.1",
- "@w3ux/extension-assets": "^0.4.0",
+ "@w3ux/extension-assets": "^1.0.0-beta.1",
"@w3ux/factories": "^1.0.0",
"@w3ux/hooks": "^1.3.1-beta.7",
- "@w3ux/react-connect-kit": "^1.8.0",
+ "@w3ux/react-connect-kit": "2.0.0-beta.2",
"@w3ux/react-odometer": "^1.1.0",
"@w3ux/react-polkicon": "^2.0.1-alpha.0",
"@w3ux/utils": "^1.1.1-beta.11",
diff --git a/packages/app/src/hooks/useBatchCallPapi/index.tsx b/packages/app/src/hooks/useBatchCallPapi/index.tsx
new file mode 100644
index 000000000..131e35f11
--- /dev/null
+++ b/packages/app/src/hooks/useBatchCallPapi/index.tsx
@@ -0,0 +1,49 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { AnyApi, MaybeAddress } from 'types';
+import { useActiveAccounts } from 'contexts/ActiveAccounts';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useProxySupportedPapi } from 'hooks/useProxySupportedPapi';
+import type { UnsafeTx } from 'hooks/useSubmitExtrinsicPapi/types';
+
+export const useBatchCallPapi = () => {
+ const { network } = useNetwork();
+ const { activeProxy } = useActiveAccounts();
+ const { isProxySupported } = useProxySupportedPapi();
+
+ const newBatchCall = (txs: UnsafeTx[], from: MaybeAddress): AnyApi => {
+ const { pApi } = ApiController.get(network);
+
+ if (!pApi) {
+ return undefined;
+ }
+
+ from = from || '';
+ const batchTx = pApi.tx.Utility.batch({
+ calls: txs.map((tx) => tx.decodedCall),
+ });
+
+ if (activeProxy && isProxySupported(batchTx, from)) {
+ return pApi.tx.Utility.batch({
+ calls: txs.map(
+ (tx) =>
+ pApi.tx.Proxy.proxy({
+ real: {
+ type: 'Id',
+ value: from,
+ },
+ force_proxy_type: null,
+ call: tx.decodedCall,
+ }).decodedCall
+ ),
+ });
+ }
+ return batchTx;
+ };
+
+ return {
+ newBatchCall,
+ };
+};
diff --git a/packages/app/src/hooks/useBondGreatestFee/index.tsx b/packages/app/src/hooks/useBondGreatestFee/index.tsx
index e058d3d2b..651cc451a 100644
--- a/packages/app/src/hooks/useBondGreatestFee/index.tsx
+++ b/packages/app/src/hooks/useBondGreatestFee/index.tsx
@@ -3,17 +3,14 @@
import BigNumber from 'bignumber.js';
import { useEffect, useMemo, useState } from 'react';
-import { useApi } from 'contexts/Api';
import { useTransferOptions } from 'contexts/TransferOptions';
import type { BondFor } from 'types';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
-interface Props {
- bondFor: BondFor;
-}
-
-export const useBondGreatestFee = ({ bondFor }: Props) => {
- const { api } = useApi();
+export const useBondGreatestFee = ({ bondFor }: { bondFor: BondFor }) => {
+ const { network } = useNetwork();
const { activeAccount } = useActiveAccounts();
const { feeReserve, getTransferOptions } = useTransferOptions();
const transferOptions = useMemo(
@@ -38,26 +35,29 @@ export const useBondGreatestFee = ({ bondFor }: Props) => {
// estimate the largest possible tx fee based on users free balance.
const txLargestFee = async () => {
+ const { pApi } = ApiController.get(network);
+
const bond = BigNumber.max(
transferrableBalance.minus(feeReserve),
0
).toString();
let tx = null;
- if (!api) {
+ if (!pApi) {
return new BigNumber(0);
}
if (bondFor === 'pool') {
- tx = api.tx.nominationPools.bondExtra({
- FreeBalance: bond,
+ tx = pApi.tx.NominationPools.bond_extra({
+ type: 'FreeBalance',
+ value: BigInt(bond),
});
} else if (bondFor === 'nominator') {
- tx = api.tx.staking.bondExtra(bond);
+ tx = pApi.tx.Staking.bond_extra({ bond });
}
if (tx) {
- const { partialFee } = await tx.paymentInfo(activeAccount || '');
- return new BigNumber(partialFee.toString());
+ const { partial_fee } = await tx.getPaymentInfo(activeAccount || '');
+ return new BigNumber(partial_fee.toString());
}
return new BigNumber(0);
};
diff --git a/packages/app/src/hooks/useProxySupportedPapi/index.tsx b/packages/app/src/hooks/useProxySupportedPapi/index.tsx
new file mode 100644
index 000000000..0c3e12a6c
--- /dev/null
+++ b/packages/app/src/hooks/useProxySupportedPapi/index.tsx
@@ -0,0 +1,66 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import {
+ UnsupportedIfUniqueController,
+ isSupportedProxyCall,
+} from 'config/proxies';
+import { useBonded } from 'contexts/Bonded';
+import { useActiveAccounts } from 'contexts/ActiveAccounts';
+import { useProxies } from 'contexts/Proxies';
+import type { MaybeAddress } from 'types';
+import type { AnyJson } from '@w3ux/types';
+import type { UnsafeTx } from 'hooks/useSubmitExtrinsicPapi/types';
+
+export const useProxySupportedPapi = () => {
+ const { getBondedAccount } = useBonded();
+ const { getProxyDelegate } = useProxies();
+ const { activeProxy } = useActiveAccounts();
+
+ // If call is from controller, & controller is different from stash, then proxy is not
+ // supported.
+ const controllerNotSupported = (c: string, f: MaybeAddress) =>
+ UnsupportedIfUniqueController.includes(c) && getBondedAccount(f) !== f;
+
+ // Determine whether the provided tx is proxy supported.
+ const isProxySupported = (tx: UnsafeTx, delegator: MaybeAddress) => {
+ // if already wrapped, return.
+ if (
+ tx?.decodedCall.type === 'Proxy' &&
+ tx?.decodedCall.value.type === 'proxy'
+ ) {
+ return true;
+ }
+
+ const proxyDelegate = getProxyDelegate(delegator, activeProxy);
+ const proxyType = proxyDelegate?.proxyType || '';
+ const pallet: string = (tx?.decodedCall.type || '').toLowerCase();
+ const method: string = (tx?.decodedCall.value.type || '').toLowerCase();
+ const call = `${pallet}.${method}`;
+
+ // If a batch call, test if every inner call is a supported proxy call.
+ if (call === 'utility.batch') {
+ return (tx?.decodedCall.value?.value?.calls || [])
+ .map((c: AnyJson) => ({
+ pallet: c.type,
+ method: c.value.type,
+ }))
+ .every(
+ (c: AnyJson) =>
+ (isSupportedProxyCall(proxyType, c.pallet, c.method) ||
+ (c.pallet === 'Proxy' && c.method === 'proxy')) &&
+ !controllerNotSupported(`${pallet}.${method}`, delegator)
+ );
+ }
+
+ // Check if the current call is a supported proxy call.
+ return (
+ isSupportedProxyCall(proxyType, pallet, method) &&
+ !controllerNotSupported(call, delegator)
+ );
+ };
+
+ return {
+ isProxySupported,
+ };
+};
diff --git a/packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx b/packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx
new file mode 100644
index 000000000..517f9c062
--- /dev/null
+++ b/packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx
@@ -0,0 +1,281 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import BigNumber from 'bignumber.js';
+import { useEffect, useRef, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { DappName, ManualSigners } from 'consts';
+import { useLedgerHardware } from 'contexts/LedgerHardware';
+import { useTxMeta } from 'contexts/TxMeta';
+import { useActiveAccounts } from 'contexts/ActiveAccounts';
+import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
+import type {
+ UnsafeTx,
+ UseSubmitExtrinsic,
+ UseSubmitExtrinsicProps,
+} from './types';
+import { NotificationsController } from 'controllers/Notifications';
+import { useExtensions } from '@w3ux/react-connect-kit';
+import { useProxySupportedPapi } from 'hooks/useProxySupportedPapi';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useBalances } from 'contexts/Balances';
+import { InvalidTxError } from 'polkadot-api';
+import { connectInjectedExtension } from 'polkadot-api/pjs-signer';
+import { formatAccountSs58 } from '@w3ux/utils';
+
+export const useSubmitExtrinsicPapi = ({
+ tx,
+ from,
+ shouldSubmit,
+ callbackSubmit,
+ callbackInBlock,
+}: UseSubmitExtrinsicProps): UseSubmitExtrinsic => {
+ const { t } = useTranslation('library');
+ const { network } = useNetwork();
+ const { getNonce } = useBalances();
+ const { activeProxy } = useActiveAccounts();
+ const { extensionsStatus } = useExtensions();
+ const { isProxySupported } = useProxySupportedPapi();
+ const { handleResetLedgerTask } = useLedgerHardware();
+ const { addPendingNonce, removePendingNonce } = useTxMeta();
+ const { getAccount, requiresManualSign } = useImportedAccounts();
+ const { txFees, setTxFees, setSender, incrementPayloadUid } = useTxMeta();
+
+ // Store given tx as a ref.
+ const txRef = useRef(tx);
+
+ // Store given submit address as a ref.
+ const fromRef = useRef(from || '');
+
+ // Store whether the transaction is in progress.
+ const [submitting, setSubmitting] = useState(false);
+
+ // Store the uid of the extrinsic.
+ const [uid] = useState(incrementPayloadUid());
+
+ // Track for one-shot transaction reset after submission.
+ const didTxReset = useRef(false);
+
+ // If proxy account is active, wrap tx in a proxy call and set the sender to the proxy account.
+ const wrapTxIfActiveProxy = () => {
+ const { pApi } = ApiController.get(network);
+
+ // if already wrapped, update fromRef and return.
+ if (
+ txRef.current?.decodedCall.type === 'Proxy' &&
+ txRef.current?.decodedCall.value.type === 'proxy'
+ ) {
+ if (activeProxy) {
+ fromRef.current = activeProxy;
+ }
+ return;
+ }
+
+ if (
+ pApi &&
+ activeProxy &&
+ txRef.current &&
+ isProxySupported(txRef.current, fromRef.current)
+ ) {
+ // update submit address to active proxy account.
+ fromRef.current = activeProxy;
+
+ // Do not wrap batch transactions. Proxy calls should already be wrapping each tx within the
+ // batch via `useBatchCall`.
+ if (
+ txRef.current?.decodedCall.type === 'Utility' &&
+ txRef.current?.decodedCall.value.type === 'batch'
+ ) {
+ return;
+ }
+
+ // Not a batch transaction: wrap tx in proxy call.
+ txRef.current = pApi.tx.Proxy.proxy({
+ real: {
+ type: 'Id',
+ value: from,
+ },
+ forceProxyType: null,
+ call: txRef.current.decodedCall,
+ });
+ }
+ };
+
+ // Calculate the estimated tx fee of the transaction.
+ const calculateEstimatedFee = async () => {
+ if (txRef.current === null) {
+ return;
+ }
+
+ // get payment info
+ const partialFee = (await txRef.current.getPaymentInfo(fromRef.current))
+ .partial_fee;
+ const partialFeeBn = new BigNumber(partialFee.toString());
+
+ // give tx fees to global useTxMeta context
+ if (partialFeeBn.toString() !== txFees.toString()) {
+ setTxFees(partialFeeBn);
+ }
+ };
+
+ // Extrinsic submission handler.
+ const onSubmit = async () => {
+ const account = getAccount(fromRef.current);
+ if (account === null || submitting || !shouldSubmit) {
+ return;
+ }
+
+ const nonce = String(getNonce(fromRef.current));
+ const { source } = account;
+ const isManualSigner = ManualSigners.includes(source);
+
+ // if `activeAccount` is imported from an extension, ensure it is enabled.
+ if (!isManualSigner) {
+ const isInstalled = Object.entries(extensionsStatus).find(
+ ([id, status]) => id === source && status === 'connected'
+ );
+
+ if (!isInstalled) {
+ throw new Error(`${t('walletNotFound')}`);
+ }
+
+ if (!window?.injectedWeb3?.[source]) {
+ throw new Error(`${t('walletNotFound')}`);
+ }
+
+ // summons extension popup if not already connected.
+ window.injectedWeb3[source].enable(DappName);
+ }
+
+ const onReady = () => {
+ addPendingNonce(nonce);
+ NotificationsController.emit({
+ title: t('pending'),
+ subtitle: t('transactionInitiated'),
+ });
+ if (callbackSubmit && typeof callbackSubmit === 'function') {
+ callbackSubmit();
+ }
+ };
+
+ const onInBlock = () => {
+ setSubmitting(false);
+ removePendingNonce(nonce);
+ NotificationsController.emit({
+ title: t('inBlock'),
+ subtitle: t('transactionInBlock'),
+ });
+ if (callbackInBlock && typeof callbackInBlock === 'function') {
+ callbackInBlock();
+ }
+ };
+
+ const onFinalizedEvent = () => {
+ NotificationsController.emit({
+ title: t('finalized'),
+ subtitle: t('transactionSuccessful'),
+ });
+ setSubmitting(false);
+ removePendingNonce(nonce);
+ };
+
+ const onFailedTx = () => {
+ NotificationsController.emit({
+ title: t('failed'),
+ subtitle: t('errorWithTransaction'),
+ });
+ setSubmitting(false);
+ removePendingNonce(nonce);
+ };
+
+ const resetTx = () => {
+ setSubmitting(false);
+ };
+
+ const onError = (type?: string) => {
+ resetTx();
+ if (type === 'ledger') {
+ handleResetLedgerTask();
+ }
+ removePendingNonce(nonce);
+ NotificationsController.emit({
+ title: t('cancelled'),
+ subtitle: t('transactionCancelled'),
+ });
+ };
+
+ const handleStatus = (status: string) => {
+ if (status === 'broadcasted') {
+ onReady();
+ }
+ if (status === 'txBestBlocksState') {
+ onInBlock();
+ }
+ };
+
+ // pre-submission state update
+ setSubmitting(true);
+
+ // handle signed transaction.
+ let signer;
+ if (requiresManualSign(fromRef.current)) {
+ // TODO: Get custom signer here.
+ } else {
+ // Get the polkadot signer for this account.
+ signer = (await connectInjectedExtension(source))
+ .getAccounts()
+ .find(
+ (a) => a.address === formatAccountSs58(fromRef.current, 42)
+ )?.polkadotSigner;
+ }
+
+ try {
+ const sub = tx.signSubmitAndWatch(signer).subscribe({
+ next: (result: { type: string }) => {
+ const eventType = result?.type;
+
+ if (!didTxReset.current) {
+ didTxReset.current = true;
+ resetTx();
+ }
+ handleStatus(eventType);
+ if (eventType === 'finalized') {
+ onFinalizedEvent();
+ sub?.unsubscribe();
+ }
+ },
+ error: (err: Error) => {
+ if (err instanceof InvalidTxError) {
+ onFailedTx();
+ }
+ sub?.unsubscribe();
+ },
+ });
+ } catch (e) {
+ onError('default');
+ }
+ };
+
+ // Refresh state upon `tx` updates.
+ useEffect(() => {
+ // update txRef to latest tx.
+ txRef.current = tx;
+ // update submit address to latest from.
+ fromRef.current = from || '';
+ // wrap tx in proxy call if active proxy & proxy supported.
+ wrapTxIfActiveProxy();
+ // ensure sender is up to date.
+ setSender(fromRef.current);
+ // re-calculate estimated tx fee.
+ calculateEstimatedFee();
+ }, [tx?.toString(), tx?.method?.args?.calls?.toString(), from]);
+
+ return {
+ uid,
+ onSubmit,
+ submitting,
+ submitAddress: fromRef.current,
+ proxySupported: isProxySupported(txRef.current, fromRef.current),
+ };
+};
diff --git a/packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts b/packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts
new file mode 100644
index 000000000..292c83817
--- /dev/null
+++ b/packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts
@@ -0,0 +1,24 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { UnsafeTransaction } from 'polkadot-api';
+import type { AnyApi, MaybeAddress } from 'types';
+
+export interface UseSubmitExtrinsicProps {
+ tx: AnyApi;
+ from: MaybeAddress;
+ shouldSubmit: boolean;
+ callbackSubmit?: () => void;
+ callbackInBlock?: () => void;
+}
+
+export interface UseSubmitExtrinsic {
+ uid: number;
+ onSubmit: () => void;
+ submitting: boolean;
+ proxySupported: boolean;
+ submitAddress: MaybeAddress;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type UnsafeTx = UnsafeTransaction;
diff --git a/yarn.lock b/yarn.lock
index 846ee4ff5..237b8fc47 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -236,17 +236,6 @@ __metadata:
languageName: node
linkType: hard
-"@chainsafe/metamask-polkadot-adapter@npm:^0.6.0":
- version: 0.6.0
- resolution: "@chainsafe/metamask-polkadot-adapter@npm:0.6.0"
- dependencies:
- "@polkadot/api": "npm:^10.9.1"
- "@polkadot/extension-inject": "npm:^0.46.5"
- "@polkadot/types-augment": "npm:^10.9.1"
- checksum: 10c0/a9cdfdd175dc6d9f6aa1d6f4515185d3f2b4089154dd0cd47749f66c6e5965cd7ff0187245763f7aafa1be49d41e1d2e8d721c78a0e831afc506fb6ff229ae15
- languageName: node
- linkType: hard
-
"@coinbase/wallet-sdk@npm:4.2.3":
version: 4.2.3
resolution: "@coinbase/wallet-sdk@npm:4.2.3"
@@ -1808,20 +1797,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/client@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
- version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
- resolution: "@polkadot-api/client@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- dependencies:
- "@polkadot-api/metadata-builders": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@polkadot-api/substrate-bindings": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@polkadot-api/substrate-client": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@polkadot-api/utils": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- peerDependencies:
- rxjs: ">=7.8.0"
- checksum: 10c0/f80744e1612446a09fdd3f5a98cdf8f9a5b9fdeddcfa083084b49e0ae63e4b4875a326487258bcbb60e6edc2fbb831436abe4a48b87942c4417ba1ee05e95648
- languageName: node
- linkType: hard
-
"@polkadot-api/codegen@npm:0.12.7":
version: 0.12.7
resolution: "@polkadot-api/codegen@npm:0.12.7"
@@ -1859,13 +1834,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/json-rpc-provider-proxy@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
- version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
- resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- checksum: 10c0/63160c2227996e1d8926a7d0281cd7a747e53e8049a63c74087425bca6a986662f46ca8e0be5b31882816199aeef1863c8ee9a7d2834d2ee1a0d1bc6dc7d61f3
- languageName: node
- linkType: hard
-
"@polkadot-api/json-rpc-provider-proxy@npm:0.2.3":
version: 0.2.3
resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.2.3"
@@ -1887,13 +1855,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/json-rpc-provider@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
- version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
- resolution: "@polkadot-api/json-rpc-provider@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- checksum: 10c0/2cc039dfd0234696e624a48d94f07b68ab3b1fc402f703b142b05f640301c47a3c5315a6ef10d2a61c31d6f93181d1240ba5b4e169e5cb8a428f5eb9613b0123
- languageName: node
- linkType: hard
-
"@polkadot-api/json-rpc-provider@npm:0.0.4":
version: 0.0.4
resolution: "@polkadot-api/json-rpc-provider@npm:0.0.4"
@@ -1928,16 +1889,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/metadata-builders@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
- version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
- resolution: "@polkadot-api/metadata-builders@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- dependencies:
- "@polkadot-api/substrate-bindings": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@polkadot-api/utils": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- checksum: 10c0/15dcba05a0c7cafaab72edc6c6246133cc25f94a158f0ac2091e3c774271cae6cf64658cefe5db9d57eb16e9a9cc8936f387547064237d129d7675e9ca27e1d3
- languageName: node
- linkType: hard
-
"@polkadot-api/metadata-builders@npm:0.3.2":
version: 0.3.2
resolution: "@polkadot-api/metadata-builders@npm:0.3.2"
@@ -2038,7 +1989,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/signers-common@npm:0.1.1":
+"@polkadot-api/signers-common@npm:0.1.1, @polkadot-api/signers-common@npm:^0.1.1":
version: 0.1.1
resolution: "@polkadot-api/signers-common@npm:0.1.1"
dependencies:
@@ -2072,18 +2023,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/substrate-bindings@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
- version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
- resolution: "@polkadot-api/substrate-bindings@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- dependencies:
- "@noble/hashes": "npm:^1.3.1"
- "@polkadot-api/utils": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@scure/base": "npm:^1.1.1"
- scale-ts: "npm:^1.6.0"
- checksum: 10c0/f6273cbb1ed74f253f83dfb9e4b46375eb7430e17e69a2f3d631ff80d8ff7b7e871cdf89639ef18635a659a60623e384c894ab2e1889d70442f7ca73c05b44e3
- languageName: node
- linkType: hard
-
"@polkadot-api/substrate-bindings@npm:0.6.0":
version: 0.6.0
resolution: "@polkadot-api/substrate-bindings@npm:0.6.0"
@@ -2108,13 +2047,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/substrate-client@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
- version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
- resolution: "@polkadot-api/substrate-client@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- checksum: 10c0/56dc28993d06a14b4091f028956f8bb179d3c602a3e3979a978eb2192233ce6ad2f12d4a583e859480521d4c75629aab1d7f0effd989da0ebb90a1b51e7ee073
- languageName: node
- linkType: hard
-
"@polkadot-api/substrate-client@npm:0.3.0":
version: 0.3.0
resolution: "@polkadot-api/substrate-client@npm:0.3.0"
@@ -2135,13 +2067,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/utils@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0":
- version: 0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0
- resolution: "@polkadot-api/utils@npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- checksum: 10c0/63c36ac45d63a4f8718d1324be0290dadfbfbb387e440d5962de13200861400a6af09a5e96b73f985fd4c27d03c93927420c8145e49e1e822653a3c223dda645
- languageName: node
- linkType: hard
-
"@polkadot-api/utils@npm:0.1.0":
version: 0.1.0
resolution: "@polkadot-api/utils@npm:0.1.0"
@@ -2174,18 +2099,18 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api-augment@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/api-augment@npm:10.13.1"
+"@polkadot/api-augment@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/api-augment@npm:12.4.2"
dependencies:
- "@polkadot/api-base": "npm:10.13.1"
- "@polkadot/rpc-augment": "npm:10.13.1"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/types-augment": "npm:10.13.1"
- "@polkadot/types-codec": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
- tslib: "npm:^2.6.2"
- checksum: 10c0/5f1faa67bc8a574fe97debc8aa7e7f6795aa437a1212121188d6bbeb1d465b47b0a1a22b8268f3136e1956dcdf0c1f9004b2a7968a275414e93b0a4e91ba7edc
+ "@polkadot/api-base": "npm:12.4.2"
+ "@polkadot/rpc-augment": "npm:12.4.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/types-augment": "npm:12.4.2"
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/4cab0d50cde43eb25d830fca93cdfe10198302d44a271aacfa274d171671ce4fa4b07bafd0886f8cf78ce10478762e337e9fe27a652080a1dc6f5823be05bcb3
languageName: node
linkType: hard
@@ -2204,16 +2129,16 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api-base@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/api-base@npm:10.13.1"
+"@polkadot/api-base@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/api-base@npm:12.4.2"
dependencies:
- "@polkadot/rpc-core": "npm:10.13.1"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
+ "@polkadot/rpc-core": "npm:12.4.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
rxjs: "npm:^7.8.1"
- tslib: "npm:^2.6.2"
- checksum: 10c0/3adaa5d3c34e16cc28a0427839c87aab7b1d022c8b6992c43dc91ab7e910d0c8e17dca9ee6b7c9e27a6486aa8878dd7deae79870d7d44ede92aba8421241c249
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/b2e7b7a3f93070b09f5992f8128a378f47a8c808a08a2890c50abcaded040ab30e8b1b5c2b693c375f2187032dc8d010d407ac14e1e39fcb984a2e0f9f05e23d
languageName: node
linkType: hard
@@ -2230,21 +2155,21 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api-derive@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/api-derive@npm:10.13.1"
+"@polkadot/api-derive@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/api-derive@npm:12.4.2"
dependencies:
- "@polkadot/api": "npm:10.13.1"
- "@polkadot/api-augment": "npm:10.13.1"
- "@polkadot/api-base": "npm:10.13.1"
- "@polkadot/rpc-core": "npm:10.13.1"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/types-codec": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
- "@polkadot/util-crypto": "npm:^12.6.2"
+ "@polkadot/api": "npm:12.4.2"
+ "@polkadot/api-augment": "npm:12.4.2"
+ "@polkadot/api-base": "npm:12.4.2"
+ "@polkadot/rpc-core": "npm:12.4.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ "@polkadot/util-crypto": "npm:^13.0.2"
rxjs: "npm:^7.8.1"
- tslib: "npm:^2.6.2"
- checksum: 10c0/91df2f399b0133bdcc19edb595e058481b1ffc63e80dbbc58c928eb04982cae1372fe7e3eda6b05888c88b68ae152f46646d080f4b940a5cca9307a681b7c78f
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/47f0698fa2b3f1adc03af93fbf7c533d8801bad52c7d8989ab019ce215bbd1c1e8d7a0c18d89839e86619ae9e93385cb7963feecc323dad79751de1496d0c23c
languageName: node
linkType: hard
@@ -2266,28 +2191,28 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api@npm:10.13.1, @polkadot/api@npm:^10.12.4, @polkadot/api@npm:^10.9.1":
- version: 10.13.1
- resolution: "@polkadot/api@npm:10.13.1"
- dependencies:
- "@polkadot/api-augment": "npm:10.13.1"
- "@polkadot/api-base": "npm:10.13.1"
- "@polkadot/api-derive": "npm:10.13.1"
- "@polkadot/keyring": "npm:^12.6.2"
- "@polkadot/rpc-augment": "npm:10.13.1"
- "@polkadot/rpc-core": "npm:10.13.1"
- "@polkadot/rpc-provider": "npm:10.13.1"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/types-augment": "npm:10.13.1"
- "@polkadot/types-codec": "npm:10.13.1"
- "@polkadot/types-create": "npm:10.13.1"
- "@polkadot/types-known": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
- "@polkadot/util-crypto": "npm:^12.6.2"
+"@polkadot/api@npm:12.4.2, @polkadot/api@npm:^12.0.2":
+ version: 12.4.2
+ resolution: "@polkadot/api@npm:12.4.2"
+ dependencies:
+ "@polkadot/api-augment": "npm:12.4.2"
+ "@polkadot/api-base": "npm:12.4.2"
+ "@polkadot/api-derive": "npm:12.4.2"
+ "@polkadot/keyring": "npm:^13.0.2"
+ "@polkadot/rpc-augment": "npm:12.4.2"
+ "@polkadot/rpc-core": "npm:12.4.2"
+ "@polkadot/rpc-provider": "npm:12.4.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/types-augment": "npm:12.4.2"
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/types-create": "npm:12.4.2"
+ "@polkadot/types-known": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ "@polkadot/util-crypto": "npm:^13.0.2"
eventemitter3: "npm:^5.0.1"
rxjs: "npm:^7.8.1"
- tslib: "npm:^2.6.2"
- checksum: 10c0/c2192c51aca790b2d8915a08e55e3b0461c49a1ce3ceccc5597cd74d68367ff0a881a0a864a0897835364482618d0a945247576573ef7c00688f1a25a5347ccc
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/64e9713508193a971e7fe830d39c625101b9dc9ce987ee38118d9a2e7e913eaeb9231cd7776b4d00ac293b23052c12ca6e7867fddacb8f7ec283017ee68ad1aa
languageName: node
linkType: hard
@@ -2316,13 +2241,13 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/extension-inject@npm:0.46.9, @polkadot/extension-inject@npm:^0.46.5":
- version: 0.46.9
- resolution: "@polkadot/extension-inject@npm:0.46.9"
+"@polkadot/extension-inject@npm:0.48.2":
+ version: 0.48.2
+ resolution: "@polkadot/extension-inject@npm:0.48.2"
dependencies:
- "@polkadot/api": "npm:^10.12.4"
- "@polkadot/rpc-provider": "npm:^10.12.4"
- "@polkadot/types": "npm:^10.12.4"
+ "@polkadot/api": "npm:^12.0.2"
+ "@polkadot/rpc-provider": "npm:^12.0.2"
+ "@polkadot/types": "npm:^12.0.2"
"@polkadot/util": "npm:^12.6.2"
"@polkadot/util-crypto": "npm:^12.6.2"
"@polkadot/x-global": "npm:^12.6.2"
@@ -2330,7 +2255,7 @@ __metadata:
peerDependencies:
"@polkadot/api": "*"
"@polkadot/util": "*"
- checksum: 10c0/6afd3f8f5b1b803004eb50ab4588035c679933533042010cf55f685d21d8f34e2d3c8644f61831098b0cbd1abe8a669b48c22a1d19d0cc06175e9ff798e9a87c
+ checksum: 10c0/c8281942bf30f31c9b5388475483197e023a113da839b9144d8c558124728e7edd48b305e9f2d7f9674a3f0b6517571b6993eb0f4d40157a796bd772094e7ca3
languageName: node
linkType: hard
@@ -2348,7 +2273,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/keyring@npm:^13.2.3":
+"@polkadot/keyring@npm:^13.0.2, @polkadot/keyring@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/keyring@npm:13.2.3"
dependencies:
@@ -2362,7 +2287,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/networks@npm:12.6.2, @polkadot/networks@npm:^12.6.2":
+"@polkadot/networks@npm:12.6.2":
version: 12.6.2
resolution: "@polkadot/networks@npm:12.6.2"
dependencies:
@@ -2373,7 +2298,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/networks@npm:13.2.3, @polkadot/networks@npm:^13.2.3":
+"@polkadot/networks@npm:13.2.3, @polkadot/networks@npm:^13.0.2, @polkadot/networks@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/networks@npm:13.2.3"
dependencies:
@@ -2384,16 +2309,16 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/rpc-augment@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/rpc-augment@npm:10.13.1"
+"@polkadot/rpc-augment@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/rpc-augment@npm:12.4.2"
dependencies:
- "@polkadot/rpc-core": "npm:10.13.1"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/types-codec": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
- tslib: "npm:^2.6.2"
- checksum: 10c0/5389ac83712cb0144e5f6b4319f76a54e8c85d455043ba688d32b233bc83202479f5506a8c8a0a7b0e8688150ca4c8d63ef57b2255e52827a5738eb600ab01ee
+ "@polkadot/rpc-core": "npm:12.4.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/8e078db8496337c16bfb474cb557aaed5cccb2c1a3b8a56ad729fea308b23745c0cf5db10212f5653b60344add2084fc5ac7521a7b08c19fd309280e539336cf
languageName: node
linkType: hard
@@ -2410,17 +2335,17 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/rpc-core@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/rpc-core@npm:10.13.1"
+"@polkadot/rpc-core@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/rpc-core@npm:12.4.2"
dependencies:
- "@polkadot/rpc-augment": "npm:10.13.1"
- "@polkadot/rpc-provider": "npm:10.13.1"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
+ "@polkadot/rpc-augment": "npm:12.4.2"
+ "@polkadot/rpc-provider": "npm:12.4.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
rxjs: "npm:^7.8.1"
- tslib: "npm:^2.6.2"
- checksum: 10c0/423479b6332eae4729076e1faa7371e7516021348ec6b4a4323a25740ea2577afdb395e767580babd854da14f63065cd4ac766a58b61263d09db64f1f6bb2599
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/4201b1d503801a672f2ceb0e6ab90226eb03c2d668879669656d73a952c556ba32e0a85c479d87ccd0aa80ce8fbc69ddde69abee462517dabc4736b3993deca6
languageName: node
linkType: hard
@@ -2438,27 +2363,27 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/rpc-provider@npm:10.13.1, @polkadot/rpc-provider@npm:^10.12.4":
- version: 10.13.1
- resolution: "@polkadot/rpc-provider@npm:10.13.1"
+"@polkadot/rpc-provider@npm:12.4.2, @polkadot/rpc-provider@npm:^12.0.2":
+ version: 12.4.2
+ resolution: "@polkadot/rpc-provider@npm:12.4.2"
dependencies:
- "@polkadot/keyring": "npm:^12.6.2"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/types-support": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
- "@polkadot/util-crypto": "npm:^12.6.2"
- "@polkadot/x-fetch": "npm:^12.6.2"
- "@polkadot/x-global": "npm:^12.6.2"
- "@polkadot/x-ws": "npm:^12.6.2"
- "@substrate/connect": "npm:0.8.8"
+ "@polkadot/keyring": "npm:^13.0.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/types-support": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ "@polkadot/util-crypto": "npm:^13.0.2"
+ "@polkadot/x-fetch": "npm:^13.0.2"
+ "@polkadot/x-global": "npm:^13.0.2"
+ "@polkadot/x-ws": "npm:^13.0.2"
+ "@substrate/connect": "npm:0.8.11"
eventemitter3: "npm:^5.0.1"
mock-socket: "npm:^9.3.1"
- nock: "npm:^13.5.0"
- tslib: "npm:^2.6.2"
+ nock: "npm:^13.5.4"
+ tslib: "npm:^2.6.3"
dependenciesMeta:
"@substrate/connect":
optional: true
- checksum: 10c0/13bc88d973a55b131bea9429831caa19b85cde73bb0c8d124bbeb1f9b5cd63d4e297a38be477e75b8930e181ab837249fec06417dc52cc5c438149313e5a2947
+ checksum: 10c0/59968dfae8ecaed840ec61c84d50953faf14d76dbcfcf61ef4acb88c9f4ef07c0c2b9c5227cb2b63801a0895d3f10edb686ae3126269eda5635f29796fa20fdf
languageName: node
linkType: hard
@@ -2486,15 +2411,27 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-augment@npm:10.13.1, @polkadot/types-augment@npm:^10.9.1":
- version: 10.13.1
- resolution: "@polkadot/types-augment@npm:10.13.1"
+"@polkadot/types-augment@npm:12.1.1":
+ version: 12.1.1
+ resolution: "@polkadot/types-augment@npm:12.1.1"
dependencies:
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/types-codec": "npm:10.13.1"
+ "@polkadot/types": "npm:12.1.1"
+ "@polkadot/types-codec": "npm:12.1.1"
"@polkadot/util": "npm:^12.6.2"
tslib: "npm:^2.6.2"
- checksum: 10c0/0686a834fd5d4db1cc74c184057cf1c47f008d3d541866cb2f2a38464c6a41cb159e5ec914b2e3d68511f6c6c7798238b58ec3bd1315a67fbb1ee073147457c6
+ checksum: 10c0/20342a217823e039f3c0cc011319429345b98472230472e3ec3563d97581ad2a20a974cdaf66c8ce2d49381a5cdf759326027b6f55bef18b396decfd0db37030
+ languageName: node
+ linkType: hard
+
+"@polkadot/types-augment@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/types-augment@npm:12.4.2"
+ dependencies:
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/9dcae5ec9fd7aaac9d3ffe2f5adb9b5c4704376018db4860215ca38805b189c5ef2f90360da0ff29d8b9a9715617bb5eabf6870bcfd8f9eeba974d6eb9b5bfab
languageName: node
linkType: hard
@@ -2510,14 +2447,25 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-codec@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/types-codec@npm:10.13.1"
+"@polkadot/types-codec@npm:12.1.1":
+ version: 12.1.1
+ resolution: "@polkadot/types-codec@npm:12.1.1"
dependencies:
"@polkadot/util": "npm:^12.6.2"
"@polkadot/x-bigint": "npm:^12.6.2"
tslib: "npm:^2.6.2"
- checksum: 10c0/8a35c492006502804a5531231c14037ab98a13f345f4e550142254e69d62d451f0caa89347ac689b92f90b582fe6ab2f1c8eca30cdf327951323b6400fca2e50
+ checksum: 10c0/d717a4ad746c5748c683fe449814a85e0c5f4b2530c2448f5950918c83f43370bdedd51ea9c5f31da8992f674c05324649f2e1d350d5b688316be345e2257893
+ languageName: node
+ linkType: hard
+
+"@polkadot/types-codec@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/types-codec@npm:12.4.2"
+ dependencies:
+ "@polkadot/util": "npm:^13.0.2"
+ "@polkadot/x-bigint": "npm:^13.0.2"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/2a56694e6998fc2afbe4fe8a9f9805eb251e880f1343af380f70c42965d30bae2249e5a5f346e675d5f78173770ebd4fa0758ed8b9f1397db8183eb686d11842
languageName: node
linkType: hard
@@ -2532,14 +2480,25 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-create@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/types-create@npm:10.13.1"
+"@polkadot/types-create@npm:12.1.1":
+ version: 12.1.1
+ resolution: "@polkadot/types-create@npm:12.1.1"
dependencies:
- "@polkadot/types-codec": "npm:10.13.1"
+ "@polkadot/types-codec": "npm:12.1.1"
"@polkadot/util": "npm:^12.6.2"
tslib: "npm:^2.6.2"
- checksum: 10c0/efe57d84f6088111b53d29db07ab9bf951f79c3e9b4875882c7a9bb0a6f1e00230e63a84cf2a850528119bbfa7f30bdfb21bba645e3922d88ff83092ea0350c5
+ checksum: 10c0/b4e3e4f93626f816a104868467b5299a19416b14b6783b576c498636d46a7d86488d623a91d5b3f106e4f7717959c90e1b9d0a65f2a60893ecb4f491ea5c8b54
+ languageName: node
+ linkType: hard
+
+"@polkadot/types-create@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/types-create@npm:12.4.2"
+ dependencies:
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/c075d07c2d3212f0ab9772cd008bfadccde7a35f6366c6704a326f8e5199fce7e7eb7959a6bd229b69fcbc3900c522892f94b08b4cd991be6e42f2a786585d0f
languageName: node
linkType: hard
@@ -2554,17 +2513,17 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-known@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/types-known@npm:10.13.1"
+"@polkadot/types-known@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/types-known@npm:12.4.2"
dependencies:
- "@polkadot/networks": "npm:^12.6.2"
- "@polkadot/types": "npm:10.13.1"
- "@polkadot/types-codec": "npm:10.13.1"
- "@polkadot/types-create": "npm:10.13.1"
- "@polkadot/util": "npm:^12.6.2"
- tslib: "npm:^2.6.2"
- checksum: 10c0/ce4e5b402e4d923a1b93475997e57bb6b7f95cc679a466c7d563d9d033872479100cf5ac72c58faaf57610602c913555ef0b4bd4672c6c76fc733c062d41959b
+ "@polkadot/networks": "npm:^13.0.2"
+ "@polkadot/types": "npm:12.4.2"
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/types-create": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/2e7fdd895c6478e102b91d7cb3428b75c34aa0b037ba9d2d2b97d350a19ed7bd6ea4f2c91c52eef4039ebec330fd1cd58a0f88fc30882c2a6623c0cae78b421a
languageName: node
linkType: hard
@@ -2582,13 +2541,13 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-support@npm:10.13.1":
- version: 10.13.1
- resolution: "@polkadot/types-support@npm:10.13.1"
+"@polkadot/types-support@npm:12.4.2":
+ version: 12.4.2
+ resolution: "@polkadot/types-support@npm:12.4.2"
dependencies:
- "@polkadot/util": "npm:^12.6.2"
- tslib: "npm:^2.6.2"
- checksum: 10c0/a9bf65b139b1c861acc198ce650e14d2014f88d30f890710baf3481caa16b44dc39122b05d34cc86211b08e082cf4e7d5680ba3a4008711fe86b70d62a65219c
+ "@polkadot/util": "npm:^13.0.2"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/0277fe88cac0f2447b3655bb5ca32dfe7dc7e35a82d22873baf95a0272a207f73853e94b3340e7e9230945dfaa8f14f93f4ffb13c8b29d449f602e8c5fe3f3c2
languageName: node
linkType: hard
@@ -2602,19 +2561,35 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types@npm:10.13.1, @polkadot/types@npm:^10.11.2, @polkadot/types@npm:^10.12.4":
- version: 10.13.1
- resolution: "@polkadot/types@npm:10.13.1"
+"@polkadot/types@npm:12.1.1":
+ version: 12.1.1
+ resolution: "@polkadot/types@npm:12.1.1"
dependencies:
"@polkadot/keyring": "npm:^12.6.2"
- "@polkadot/types-augment": "npm:10.13.1"
- "@polkadot/types-codec": "npm:10.13.1"
- "@polkadot/types-create": "npm:10.13.1"
+ "@polkadot/types-augment": "npm:12.1.1"
+ "@polkadot/types-codec": "npm:12.1.1"
+ "@polkadot/types-create": "npm:12.1.1"
"@polkadot/util": "npm:^12.6.2"
"@polkadot/util-crypto": "npm:^12.6.2"
rxjs: "npm:^7.8.1"
tslib: "npm:^2.6.2"
- checksum: 10c0/1fe50d7ba10368dd944fec0e2da740f8c665c1c417362ab5ed1587d9083259c65064e04a862443d1a6c9f1da86b8dee6a4945e711064f0318895a38ad1303e3b
+ checksum: 10c0/46395b18dc78d7d8295df6a80fc8a00d73d942ffa2ef8bd7fc6591ac3d018f70c0765ac54b848c508514196c7bb302fc08ac80779ca1431f57c423b20c7080ac
+ languageName: node
+ linkType: hard
+
+"@polkadot/types@npm:12.4.2, @polkadot/types@npm:^12.0.2":
+ version: 12.4.2
+ resolution: "@polkadot/types@npm:12.4.2"
+ dependencies:
+ "@polkadot/keyring": "npm:^13.0.2"
+ "@polkadot/types-augment": "npm:12.4.2"
+ "@polkadot/types-codec": "npm:12.4.2"
+ "@polkadot/types-create": "npm:12.4.2"
+ "@polkadot/util": "npm:^13.0.2"
+ "@polkadot/util-crypto": "npm:^13.0.2"
+ rxjs: "npm:^7.8.1"
+ tslib: "npm:^2.6.3"
+ checksum: 10c0/bdea1658a367678a158d5d6ba6224a081cfd5fb38b6d56c360321e40628a23261261c869e7ab1ac0c89c0140777f532963c46999e5fb0f13233599a32eabdf99
languageName: node
linkType: hard
@@ -2654,7 +2629,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/util-crypto@npm:13.2.3, @polkadot/util-crypto@npm:^13.1.1, @polkadot/util-crypto@npm:^13.2.3":
+"@polkadot/util-crypto@npm:13.2.3, @polkadot/util-crypto@npm:^13.0.2, @polkadot/util-crypto@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/util-crypto@npm:13.2.3"
dependencies:
@@ -2689,7 +2664,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/util@npm:13.2.3, @polkadot/util@npm:^13.1.1, @polkadot/util@npm:^13.2.3":
+"@polkadot/util@npm:13.2.3, @polkadot/util@npm:^13.0.2, @polkadot/util@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/util@npm:13.2.3"
dependencies:
@@ -2794,7 +2769,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-bigint@npm:13.2.3, @polkadot/x-bigint@npm:^13.2.3":
+"@polkadot/x-bigint@npm:13.2.3, @polkadot/x-bigint@npm:^13.0.2, @polkadot/x-bigint@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/x-bigint@npm:13.2.3"
dependencies:
@@ -2804,18 +2779,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-fetch@npm:^12.6.2":
- version: 12.6.2
- resolution: "@polkadot/x-fetch@npm:12.6.2"
- dependencies:
- "@polkadot/x-global": "npm:12.6.2"
- node-fetch: "npm:^3.3.2"
- tslib: "npm:^2.6.2"
- checksum: 10c0/c4e34c28f4374db3b6795b31f63434b4241896a82cd1a0aa81196c7dbe8aa345069a39d27d5c3af214d8d2824154c6fe1fcbe9cb22af32f9a2c3fd22dc4b8583
- languageName: node
- linkType: hard
-
-"@polkadot/x-fetch@npm:^13.2.3":
+"@polkadot/x-fetch@npm:^13.0.2, @polkadot/x-fetch@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/x-fetch@npm:13.2.3"
dependencies:
@@ -2835,7 +2799,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-global@npm:13.2.3, @polkadot/x-global@npm:^13.2.3":
+"@polkadot/x-global@npm:13.2.3, @polkadot/x-global@npm:^13.0.2, @polkadot/x-global@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/x-global@npm:13.2.3"
dependencies:
@@ -2910,18 +2874,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-ws@npm:^12.6.2":
- version: 12.6.2
- resolution: "@polkadot/x-ws@npm:12.6.2"
- dependencies:
- "@polkadot/x-global": "npm:12.6.2"
- tslib: "npm:^2.6.2"
- ws: "npm:^8.15.1"
- checksum: 10c0/15565803a34aa7d6654c4c05725f5f44e504caa69f590523c5569fcbd66cf1e467de03e3e13a4d71bb60efceb28c60fd5719bee5efd721c020cf470025bbeb29
- languageName: node
- linkType: hard
-
-"@polkadot/x-ws@npm:^13.2.3":
+"@polkadot/x-ws@npm:^13.0.2, @polkadot/x-ws@npm:^13.2.3":
version: 13.2.3
resolution: "@polkadot/x-ws@npm:13.2.3"
dependencies:
@@ -2932,12 +2885,13 @@ __metadata:
languageName: node
linkType: hard
-"@polkagate/extension-dapp@npm:^0.46.13":
- version: 0.46.13
- resolution: "@polkagate/extension-dapp@npm:0.46.13"
+"@polkagate/extension-dapp@npm:^0.48.2":
+ version: 0.48.2
+ resolution: "@polkagate/extension-dapp@npm:0.48.2"
dependencies:
- "@polkadot/extension-inject": "npm:0.46.9"
- "@polkadot/types": "npm:^10.11.2"
+ "@metamask/utils": "npm:^9.0.0"
+ "@polkadot/extension-inject": "npm:0.48.2"
+ "@polkadot/types": "npm:12.1.1"
"@polkadot/util": "npm:^12.6.2"
"@polkadot/util-crypto": "npm:^12.6.2"
tslib: "npm:^2.6.2"
@@ -2945,7 +2899,7 @@ __metadata:
"@polkadot/api": "*"
"@polkadot/util": "*"
"@polkadot/util-crypto": "*"
- checksum: 10c0/fecad5ba8ed04c7a745b5870c75d67636dd8bbe8230a809aad443d73dcac3ba4d0bc4ba164317564f1e1fcb425e47c0c2189d5ada583e39975ec64b47254fa17
+ checksum: 10c0/87dc06ff885533135ee4fde2f74bb9809ce3ed140fe2e3baef999831537ae3c537e014140f9c8e49cdf32c1f912194b58970e42161cd9f4210dcbca5cedc35f1
languageName: node
linkType: hard
@@ -3448,7 +3402,7 @@ __metadata:
languageName: node
linkType: hard
-"@substrate/connect-known-chains@npm:^1.1.1, @substrate/connect-known-chains@npm:^1.1.5, @substrate/connect-known-chains@npm:^1.7.0":
+"@substrate/connect-known-chains@npm:^1.1.5, @substrate/connect-known-chains@npm:^1.7.0":
version: 1.7.0
resolution: "@substrate/connect-known-chains@npm:1.7.0"
checksum: 10c0/454f115eed8c2299b9ba66c8c3328af80767c501fb15a4e54e6788cc5d9ab6289c91a44a215dbaab8df4fda41063bafff5eee3926b43cd8787af86610e45c673
@@ -3467,18 +3421,6 @@ __metadata:
languageName: node
linkType: hard
-"@substrate/connect@npm:0.8.8":
- version: 0.8.8
- resolution: "@substrate/connect@npm:0.8.8"
- dependencies:
- "@substrate/connect-extension-protocol": "npm:^2.0.0"
- "@substrate/connect-known-chains": "npm:^1.1.1"
- "@substrate/light-client-extension-helpers": "npm:^0.0.4"
- smoldot: "npm:2.0.22"
- checksum: 10c0/d2507a5c2392523c31b1e25a4b0955b7c271406d527511c5ceab561fff0d8788262d638ff996dc2978464998f5db78cf373b34d2af86b040686c86f36093ec65
- languageName: node
- linkType: hard
-
"@substrate/connect@npm:^2.0.1":
version: 2.0.1
resolution: "@substrate/connect@npm:2.0.1"
@@ -3498,23 +3440,6 @@ __metadata:
languageName: node
linkType: hard
-"@substrate/light-client-extension-helpers@npm:^0.0.4":
- version: 0.0.4
- resolution: "@substrate/light-client-extension-helpers@npm:0.0.4"
- dependencies:
- "@polkadot-api/client": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@polkadot-api/json-rpc-provider": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@polkadot-api/json-rpc-provider-proxy": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@polkadot-api/substrate-client": "npm:0.0.1-492c132563ea6b40ae1fc5470dec4cd18768d182.1.0"
- "@substrate/connect-extension-protocol": "npm:^2.0.0"
- "@substrate/connect-known-chains": "npm:^1.1.1"
- rxjs: "npm:^7.8.1"
- peerDependencies:
- smoldot: 2.x
- checksum: 10c0/51e44ab2f3efaf8482047d3ed89e51327b54f53bd9d4169ce3738daf22e0afa849560cfd1f487ae809ea9adfdb93812f1cb74329d44cf686c0b552493b47b122
- languageName: node
- linkType: hard
-
"@substrate/light-client-extension-helpers@npm:^1.0.0":
version: 1.0.0
resolution: "@substrate/light-client-extension-helpers@npm:1.0.0"
@@ -4168,12 +4093,12 @@ __metadata:
languageName: node
linkType: hard
-"@w3ux/extension-assets@npm:0.4.0, @w3ux/extension-assets@npm:^0.4.0":
- version: 0.4.0
- resolution: "@w3ux/extension-assets@npm:0.4.0"
+"@w3ux/extension-assets@npm:1.0.0-beta.1, @w3ux/extension-assets@npm:^1.0.0-beta.1":
+ version: 1.0.0-beta.1
+ resolution: "@w3ux/extension-assets@npm:1.0.0-beta.1"
peerDependencies:
react: ^18
- checksum: 10c0/8cacff647d2d9c8deef43e83f57cfeb30a252cb716afb18c048b876012b9ce8f10e24d2a79f91e180014a46f9c9ca3346fd061fd6b9f98175881176bee90d4a2
+ checksum: 10c0/bb9d43db351e333d7fa6b49977ef2ce7077bfe7d855dd0960f5e9e0e08d35bfe92b6431f35a74d3140b3fb4642296db7d96b188c80cce2e393c2c9c066244983
languageName: node
linkType: hard
@@ -4186,15 +4111,6 @@ __metadata:
languageName: node
linkType: hard
-"@w3ux/hooks@npm:^1.1.0":
- version: 1.2.1
- resolution: "@w3ux/hooks@npm:1.2.1"
- peerDependencies:
- react: ^18
- checksum: 10c0/542eae337e26c2202b53625ee7178bcf8fd748aac5b37c8851ef143251a09e37bf8a95916039661dcf76fe31004d3231c87d2dad6237251dc843351282173d72
- languageName: node
- linkType: hard
-
"@w3ux/hooks@npm:^1.3.1-beta.7":
version: 1.3.1-beta.7
resolution: "@w3ux/hooks@npm:1.3.1-beta.7"
@@ -4207,18 +4123,17 @@ __metadata:
languageName: node
linkType: hard
-"@w3ux/react-connect-kit@npm:^1.8.0":
- version: 1.8.0
- resolution: "@w3ux/react-connect-kit@npm:1.8.0"
+"@w3ux/react-connect-kit@npm:2.0.0-beta.2":
+ version: 2.0.0-beta.2
+ resolution: "@w3ux/react-connect-kit@npm:2.0.0-beta.2"
dependencies:
- "@chainsafe/metamask-polkadot-adapter": "npm:^0.6.0"
- "@polkagate/extension-dapp": "npm:^0.46.13"
- "@w3ux/extension-assets": "npm:0.4.0"
- "@w3ux/hooks": "npm:^1.1.0"
- "@w3ux/utils": "npm:^0.9.0"
+ "@polkagate/extension-dapp": "npm:^0.48.2"
+ "@w3ux/extension-assets": "npm:1.0.0-beta.1"
+ "@w3ux/hooks": "npm:^1.3.1-beta.7"
+ "@w3ux/utils": "npm:^1.1.1-beta.11"
peerDependencies:
"@polkadot/api": ^11
- checksum: 10c0/8023634fdcd2a2fd50e6774f47d10ccc6c83c608821228372958f5bf21317830ce12a805c0306a5a6594c9b19375c1b2603602a1779f7e1fdf8579940b8fc633
+ checksum: 10c0/8db87ebe1a5ff9eac3a275e05043c8f920283b75edd193393ee27898708673aa034fd4ed7a71a1ffc915e477f1c1a33bb5159d023b8a2fdaa164cc9a8f573113
languageName: node
linkType: hard
@@ -4253,17 +4168,6 @@ __metadata:
languageName: node
linkType: hard
-"@w3ux/utils@npm:^0.9.0":
- version: 0.9.1
- resolution: "@w3ux/utils@npm:0.9.1"
- dependencies:
- "@polkadot/util": "npm:^13.1.1"
- "@polkadot/util-crypto": "npm:^13.1.1"
- bignumber.js: "npm:^9.1.1"
- checksum: 10c0/624ca3fd80cd5a0ed16b28342b41d643cc1aac7dbe68e00f3c4a9e460da21ac28d09e86582aad7c642e5907069c4544705c3bc638d836625916694e21774861c
- languageName: node
- linkType: hard
-
"@w3ux/utils@npm:^1.1.1-beta.11":
version: 1.1.1-beta.11
resolution: "@w3ux/utils@npm:1.1.1-beta.11"
@@ -4878,14 +4782,16 @@ __metadata:
"@fortawesome/react-fontawesome": "npm:^0.2.2"
"@ledgerhq/hw-transport-webhid": "npm:^6.29.2"
"@polkadot-api/merkleize-metadata": "npm:^1.1.4"
+ "@polkadot-api/signers-common": "npm:^0.1.1"
+ "@polkadot-api/substrate-bindings": "npm:^0.9.3"
"@polkadot/api": "npm:^14.3.1"
"@polkadot/rpc-provider": "npm:^14.3.1"
"@polkawatch/ddp-client": "npm:^2.0.20"
"@substrate/connect": "npm:^2.0.1"
- "@w3ux/extension-assets": "npm:^0.4.0"
+ "@w3ux/extension-assets": "npm:^1.0.0-beta.1"
"@w3ux/factories": "npm:^1.0.0"
"@w3ux/hooks": "npm:^1.3.1-beta.7"
- "@w3ux/react-connect-kit": "npm:^1.8.0"
+ "@w3ux/react-connect-kit": "npm:2.0.0-beta.2"
"@w3ux/react-odometer": "npm:^1.1.0"
"@w3ux/react-polkicon": "npm:^2.0.1-alpha.0"
"@w3ux/utils": "npm:^1.1.1-beta.11"
@@ -5128,7 +5034,7 @@ __metadata:
languageName: node
linkType: hard
-"bignumber.js@npm:^9.1.1, bignumber.js@npm:^9.1.2":
+"bignumber.js@npm:^9.1.2":
version: 9.1.2
resolution: "bignumber.js@npm:9.1.2"
checksum: 10c0/e17786545433f3110b868725c449fa9625366a6e675cd70eb39b60938d6adbd0158cb4b3ad4f306ce817165d37e63f4aa3098ba4110db1d9a3b9f66abfbaf10d
@@ -9014,7 +8920,7 @@ __metadata:
languageName: node
linkType: hard
-"nock@npm:^13.5.0, nock@npm:^13.5.5":
+"nock@npm:^13.5.4, nock@npm:^13.5.5":
version: 13.5.6
resolution: "nock@npm:13.5.6"
dependencies:
@@ -10889,15 +10795,6 @@ __metadata:
languageName: node
linkType: hard
-"smoldot@npm:2.0.22":
- version: 2.0.22
- resolution: "smoldot@npm:2.0.22"
- dependencies:
- ws: "npm:^8.8.1"
- checksum: 10c0/fa439bebfe0d0d46e4da342a313d0653fd56557b6459b5ba3db1fd6bcfb345e9d9577c27e1f6692e67dec0206addb95de6b594c17041729f5689b4b123974495
- languageName: node
- linkType: hard
-
"smoldot@npm:2.0.26":
version: 2.0.26
resolution: "smoldot@npm:2.0.26"
@@ -11654,7 +11551,7 @@ __metadata:
languageName: node
linkType: hard
-"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.7.0, tslib@npm:^2.8.0":
+"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3, tslib@npm:^2.7.0, tslib@npm:^2.8.0":
version: 2.8.1
resolution: "tslib@npm:2.8.1"
checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
@@ -12721,7 +12618,7 @@ __metadata:
languageName: node
linkType: hard
-"ws@npm:8.18.0, ws@npm:^8.15.1, ws@npm:^8.18.0, ws@npm:^8.8.1":
+"ws@npm:8.18.0, ws@npm:^8.18.0, ws@npm:^8.8.1":
version: 8.18.0
resolution: "ws@npm:8.18.0"
peerDependencies:
From b7e12a1c548d7a80a76c18170ce040c983fe1141 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 11:38:45 +0700
Subject: [PATCH 58/84] tx submission via papi
---
.../src/canvas/CreatePool/Summary/index.tsx | 41 ++-
.../src/canvas/JoinPool/Overview/JoinForm.tsx | 22 +-
.../src/canvas/JoinPool/Overview/Stats.tsx | 18 +-
.../src/canvas/ManageNominations/index.tsx | 22 +-
.../canvas/NominatorSetup/Summary/index.tsx | 28 +-
.../PoolMembers/Prompts/UnbondMember.tsx | 18 +-
.../PoolMembers/Prompts/WithdrawMember.tsx | 13 +-
.../src/contexts/Pools/ActivePool/index.tsx | 10 +-
.../app/src/contexts/WalletConnect/index.tsx | 26 +-
packages/app/src/hooks/useBatchCall/index.tsx | 43 +--
.../app/src/hooks/useBatchCallPapi/index.tsx | 49 ---
.../src/hooks/useBondGreatestFee/index.tsx | 8 +-
.../app/src/hooks/useBuildPayload/index.tsx | 113 -------
.../app/src/hooks/useProxySupported/index.tsx | 21 +-
.../src/hooks/useProxySupportedPapi/index.tsx | 66 ----
.../src/hooks/useSubmitExtrinsic/index.tsx | 215 ++++++--------
.../app/src/hooks/useSubmitExtrinsic/types.ts | 4 +
.../hooks/useSubmitExtrinsicPapi/index.tsx | 281 ------------------
.../src/hooks/useSubmitExtrinsicPapi/types.ts | 24 --
.../ManualSign/WalletConnect/index.tsx | 10 +-
packages/app/src/modals/Bond/index.tsx | 20 +-
.../app/src/modals/ClaimPayouts/Forms.tsx | 21 +-
packages/app/src/modals/ClaimReward/index.tsx | 22 +-
.../src/modals/ManageFastUnstake/index.tsx | 14 +-
.../Forms/ClaimCommission/index.tsx | 11 +-
.../ManagePool/Forms/LeavePool/index.tsx | 17 +-
.../Forms/ManageCommission/index.tsx | 58 ++--
.../ManagePool/Forms/RenamePool/index.tsx | 16 +-
.../Forms/SetClaimPermission/index.tsx | 16 +-
.../ManagePool/Forms/SetPoolState/index.tsx | 25 +-
.../app/src/modals/StopNominations/index.tsx | 14 +-
packages/app/src/modals/Unbond/index.tsx | 15 +-
.../app/src/modals/UnlockChunks/Forms.tsx | 28 +-
packages/app/src/modals/Unstake/index.tsx | 17 +-
packages/app/src/modals/UpdatePayee/index.tsx | 20 +-
35 files changed, 465 insertions(+), 881 deletions(-)
delete mode 100644 packages/app/src/hooks/useBatchCallPapi/index.tsx
delete mode 100644 packages/app/src/hooks/useBuildPayload/index.tsx
delete mode 100644 packages/app/src/hooks/useProxySupportedPapi/index.tsx
delete mode 100644 packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx
delete mode 100644 packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts
diff --git a/packages/app/src/canvas/CreatePool/Summary/index.tsx b/packages/app/src/canvas/CreatePool/Summary/index.tsx
index ff55af33c..149cd7058 100644
--- a/packages/app/src/canvas/CreatePool/Summary/index.tsx
+++ b/packages/app/src/canvas/CreatePool/Summary/index.tsx
@@ -10,7 +10,6 @@ import { useBondedPools } from 'contexts/Pools/BondedPools';
import { useSetup } from 'contexts/Setup';
import { Warning } from 'library/Form/Warning';
import { useBatchCall } from 'hooks/useBatchCall';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Header } from 'library/SetupSteps/Header';
import { MotionContainer } from 'library/SetupSteps/MotionContainer';
import type { SetupStepProps } from 'library/SetupSteps/types';
@@ -21,14 +20,17 @@ import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
import { SummaryWrapper } from './Wrapper';
import { useOverlay } from 'kits/Overlay/Provider';
+import { ApiController } from 'controllers/Api';
+import { Binary } from 'polkadot-api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const Summary = ({ section }: SetupStepProps) => {
const { t } = useTranslation('pages');
const {
- api,
poolsConfig: { lastPoolId },
} = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { newBatchCall } = useBatchCall();
@@ -45,7 +47,8 @@ export const Summary = ({ section }: SetupStepProps) => {
const { metadata, bond, roles, nominations } = progress;
const getTxs = () => {
- if (!activeAccount || !api) {
+ const { pApi } = ApiController.get(network);
+ if (!activeAccount || !pApi) {
return null;
}
@@ -56,14 +59,30 @@ export const Summary = ({ section }: SetupStepProps) => {
const bondToSubmit = unitToPlanck(bond, units).toString();
const txs = [
- api.tx.nominationPools.create(
- bondToSubmit,
- roles?.root || activeAccount,
- roles?.nominator || activeAccount,
- roles?.bouncer || activeAccount
- ),
- api.tx.nominationPools.nominate(poolId.toString(), targetsToSubmit),
- api.tx.nominationPools.setMetadata(poolId.toString(), metadata),
+ pApi.tx.NominationPools.create({
+ amount: BigInt(bondToSubmit.toString()),
+ root: {
+ type: 'Id',
+ value: roles?.root || activeAccount,
+ },
+ nominator: {
+ type: 'Id',
+ value: roles?.nominator || activeAccount,
+ },
+ bouncer: {
+ type: 'Id',
+ value: roles?.bouncer || activeAccount,
+ },
+ }),
+
+ pApi.tx.NominationPools.nominate({
+ pool_id: poolId.toNumber(),
+ validators: targetsToSubmit,
+ }),
+ pApi.tx.NominationPools.set_metadata({
+ pool_id: poolId.toNumber(),
+ metadata: Binary.fromHex(metadata),
+ }),
];
return newBatchCall(txs, activeAccount);
};
diff --git a/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx b/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx
index 31024e3fd..51ac1f894 100644
--- a/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx
+++ b/packages/app/src/canvas/JoinPool/Overview/JoinForm.tsx
@@ -12,9 +12,6 @@ import { JoinFormWrapper } from '../Wrappers';
import { ClaimPermissionInput } from 'library/Form/ClaimPermissionInput';
import { BondFeedback } from 'library/Form/Bond/BondFeedback';
import { useBondGreatestFee } from 'hooks/useBondGreatestFee';
-import { useApi } from 'contexts/Api';
-import { useBatchCall } from 'hooks/useBatchCall';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { useOverlay } from 'kits/Overlay/Provider';
import { useSetup } from 'contexts/Setup';
import { defaultPoolProgress } from 'contexts/Setup/defaults';
@@ -24,11 +21,14 @@ import type { OverviewSectionProps } from '../types';
import { defaultClaimPermission } from 'controllers/ActivePools/defaults';
import { useTranslation } from 'react-i18next';
import { planckToUnitBn } from 'library/Utils';
+import { ApiController } from 'controllers/Api';
+import { useBatchCall } from 'hooks/useBatchCall';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const JoinForm = ({ bondedPool }: OverviewSectionProps) => {
const { t } = useTranslation();
- const { api } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const {
@@ -72,8 +72,9 @@ export const JoinForm = ({ bondedPool }: OverviewSectionProps) => {
// Get transaction for submission.
const getTx = () => {
+ const { pApi } = ApiController.get(network);
const tx = null;
- if (!api || !claimPermission || !formValid) {
+ if (!pApi || !claimPermission || !formValid) {
return tx;
}
@@ -81,11 +82,18 @@ export const JoinForm = ({ bondedPool }: OverviewSectionProps) => {
!bondValid ? '0' : bond.bond,
units
).toString();
- const txs = [api.tx.nominationPools.join(bondToSubmit, bondedPool.id)];
+ const txs = [
+ pApi.tx.NominationPools.join({
+ amount: BigInt(bondToSubmit),
+ pool_id: bondedPool.id,
+ }),
+ ];
// If claim permission is not the default, add it to tx.
if (claimPermission !== defaultClaimPermission) {
- txs.push(api.tx.nominationPools.setClaimPermission(claimPermission));
+ txs.push(
+ pApi.tx.NominationPools.set_claim_permission({ type: claimPermission })
+ );
}
if (txs.length === 1) {
diff --git a/packages/app/src/canvas/JoinPool/Overview/Stats.tsx b/packages/app/src/canvas/JoinPool/Overview/Stats.tsx
index f7b9e69e5..4722836a0 100644
--- a/packages/app/src/canvas/JoinPool/Overview/Stats.tsx
+++ b/packages/app/src/canvas/JoinPool/Overview/Stats.tsx
@@ -15,6 +15,7 @@ import { StyledLoader } from 'library/PoolSync/Loader';
import type { CSSProperties } from 'styled-components';
import { PoolSync } from 'library/PoolSync';
import { planckToUnitBn } from 'library/Utils';
+import { ApiController } from 'controllers/Api';
export const Stats = ({
bondedPool,
@@ -23,13 +24,14 @@ export const Stats = ({
}: OverviewSectionProps) => {
const { t } = useTranslation('library');
const {
+ network,
networkData: {
units,
unit,
brand: { token: Token },
},
} = useNetwork();
- const { isReady, api } = useApi();
+ const { isReady } = useApi();
const { getPoolRewardPoints } = usePoolPerformance();
const poolRewardPoints = getPoolRewardPoints(performanceKey);
const rawEraRewardPoints = Object.values(
@@ -41,16 +43,16 @@ export const Stats = ({
// Fetches the balance of the bonded pool.
const getPoolBalance = async () => {
- if (!api) {
+ const { pApi } = ApiController.get(network);
+ if (!pApi) {
return;
}
- const balance = (
- await api.call.nominationPoolsApi.pointsToBalance(
- bondedPool.id,
- rmCommas(bondedPool.points)
- )
- ).toString();
+ const apiResult = await pApi.apis.NominationPoolsApi.points_to_balance(
+ bondedPool.id,
+ BigInt(rmCommas(bondedPool.points))
+ );
+ const balance = new BigNumber(apiResult?.toString() || 0);
if (balance) {
setPoolBalance(new BigNumber(balance));
diff --git a/packages/app/src/canvas/ManageNominations/index.tsx b/packages/app/src/canvas/ManageNominations/index.tsx
index 435806903..105d08abe 100644
--- a/packages/app/src/canvas/ManageNominations/index.tsx
+++ b/packages/app/src/canvas/ManageNominations/index.tsx
@@ -10,7 +10,6 @@ import { useApi } from 'contexts/Api';
import { faTimes } from '@fortawesome/free-solid-svg-icons';
import { usePrompt } from 'contexts/Prompt';
import { useHelp } from 'contexts/Help';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { useBonded } from 'contexts/Bonded';
import { useActivePool } from 'contexts/Pools/ActivePool';
@@ -24,6 +23,9 @@ import { RevertPrompt } from './Prompts/RevertPrompt';
import { CanvasSubmitTxFooter, CanvasFullScreenWrapper } from '../Wrappers';
import { NotificationsController } from 'controllers/Notifications';
import { ButtonHelp, ButtonPrimary, ButtonPrimaryInvert } from 'ui-buttons';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const ManageNominations = () => {
const { t } = useTranslation('library');
@@ -32,8 +34,9 @@ export const ManageNominations = () => {
setCanvasStatus,
config: { options },
} = useOverlay().canvas;
+ const { consts } = useApi();
const { openHelp } = useHelp();
- const { consts, api } = useApi();
+ const { network } = useNetwork();
const { activePool } = useActivePool();
const { getBondedAccount } = useBonded();
const { activeAccount } = useActiveAccounts();
@@ -90,8 +93,9 @@ export const ManageNominations = () => {
// Tx to submit.
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!valid || !api) {
+ if (!valid || !pApi) {
return tx;
}
@@ -100,16 +104,22 @@ export const ManageNominations = () => {
isPool
? nominee.address
: {
- Id: nominee.address,
+ type: 'Id',
+ value: nominee.address,
}
);
if (isPool) {
if (activePool) {
- tx = api.tx.nominationPools.nominate(activePool.id, targetsToSubmit);
+ tx = pApi.tx.NominationPools.nominate({
+ pool_id: activePool.id,
+ validators: targetsToSubmit,
+ });
}
} else {
- tx = api.tx.staking.nominate(targetsToSubmit);
+ tx = pApi.tx.Staking.nominate({
+ targets: targetsToSubmit,
+ });
}
return tx;
};
diff --git a/packages/app/src/canvas/NominatorSetup/Summary/index.tsx b/packages/app/src/canvas/NominatorSetup/Summary/index.tsx
index 5a1bf88ce..8555e6de6 100644
--- a/packages/app/src/canvas/NominatorSetup/Summary/index.tsx
+++ b/packages/app/src/canvas/NominatorSetup/Summary/index.tsx
@@ -8,24 +8,24 @@ import BigNumber from 'bignumber.js';
import { useTranslation } from 'react-i18next';
import { useSetup } from 'contexts/Setup';
import { Warning } from 'library/Form/Warning';
-import { useBatchCall } from 'hooks/useBatchCall';
import { usePayeeConfig } from 'hooks/usePayeeConfig';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Header } from 'library/SetupSteps/Header';
import { MotionContainer } from 'library/SetupSteps/MotionContainer';
import type { SetupStepProps } from 'library/SetupSteps/types';
import { SubmitTx } from 'library/SubmitTx';
import { useNetwork } from 'contexts/Network';
-import { useApi } from 'contexts/Api';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
import { SummaryWrapper } from './Wrapper';
import { useOverlay } from 'kits/Overlay/Provider';
+import { useBatchCall } from 'hooks/useBatchCall';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const Summary = ({ section }: SetupStepProps) => {
const { t } = useTranslation('pages');
- const { api } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { newBatchCall } = useBatchCall();
@@ -40,28 +40,36 @@ export const Summary = ({ section }: SetupStepProps) => {
const { bond, nominations, payee } = progress;
const getTxs = () => {
- if (!activeAccount || !api) {
+ const { pApi } = ApiController.get(network);
+ if (!activeAccount || !pApi) {
return null;
}
const targetsToSubmit = nominations.map(
({ address }: { address: string }) => ({
- Id: address,
+ type: 'Id',
+ value: address,
})
);
const payeeToSubmit =
payee.destination === 'Account'
? {
- Account: payee.account,
+ type: 'Account',
+ value: payee.account,
}
- : payee.destination;
+ : {
+ type: payee.destination,
+ };
const bondToSubmit = unitToPlanck(bond || '0', units).toString();
const txs = [
- api.tx.staking.bond(bondToSubmit, payeeToSubmit),
- api.tx.staking.nominate(targetsToSubmit),
+ pApi.tx.Staking.bond({
+ value: BigInt(bondToSubmit),
+ payee: payeeToSubmit,
+ }),
+ pApi.tx.Staking.nominate({ targets: targetsToSubmit }),
];
return newBatchCall(txs, activeAccount);
};
diff --git a/packages/app/src/canvas/PoolMembers/Prompts/UnbondMember.tsx b/packages/app/src/canvas/PoolMembers/Prompts/UnbondMember.tsx
index 8a5bf0900..e51b479e9 100644
--- a/packages/app/src/canvas/PoolMembers/Prompts/UnbondMember.tsx
+++ b/packages/app/src/canvas/PoolMembers/Prompts/UnbondMember.tsx
@@ -11,7 +11,6 @@ import { useApi } from 'contexts/Api';
import { Warning } from 'library/Form/Warning';
import { useErasToTimeLeft } from 'hooks/useErasToTimeLeft';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { timeleftAsString, planckToUnitBn } from 'library/Utils';
import { SubmitTx } from 'library/SubmitTx';
import { StaticNote } from 'modals/Utils/StaticNote';
@@ -23,6 +22,8 @@ import { Title } from 'library/Prompt/Title';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ModalNotes } from 'kits/Overlay/structure/ModalNotes';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const UnbondMember = ({
who,
@@ -32,8 +33,9 @@ export const UnbondMember = ({
member: PoolMembership;
}) => {
const { t } = useTranslation('modals');
- const { api, consts } = useApi();
+ const { consts } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { closePrompt } = usePrompt();
@@ -71,8 +73,9 @@ export const UnbondMember = ({
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!api || !activeAccount) {
+ if (!pApi || !activeAccount) {
return tx;
}
// remove decimal errors
@@ -80,7 +83,14 @@ export const UnbondMember = ({
!bondValid ? '0' : bond.bond,
units
).toString();
- tx = api.tx.nominationPools.unbond(who, bondToSubmit);
+
+ tx = pApi.tx.NominationPools.unbond({
+ member_account: {
+ type: 'Id',
+ value: who,
+ },
+ unbonding_points: BigInt(bondToSubmit),
+ });
return tx;
};
diff --git a/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx b/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx
index b508a029e..715a280c8 100644
--- a/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx
+++ b/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx
@@ -10,7 +10,6 @@ import { useApi } from 'contexts/Api';
import { usePoolMembers } from 'contexts/Pools/PoolMembers';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import { useNetwork } from 'contexts/Network';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
@@ -22,6 +21,8 @@ import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ModalNotes } from 'kits/Overlay/structure/ModalNotes';
import { planckToUnitBn } from 'library/Utils';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const WithdrawMember = ({
who,
@@ -34,6 +35,7 @@ export const WithdrawMember = ({
}) => {
const { t } = useTranslation('modals');
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { closePrompt } = usePrompt();
@@ -65,11 +67,18 @@ export const WithdrawMember = ({
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
if (!valid || !api) {
return tx;
}
- tx = api.tx.nominationPools.withdrawUnbonded(who, historyDepth.toString());
+ tx = pApi.tx.NominationPools.withdraw_unbonded({
+ member_account: {
+ type: 'Id',
+ value: who,
+ },
+ num_slashing_spans: historyDepth.toNumber(),
+ });
return tx;
};
const submitExtrinsic = useSubmitExtrinsic({
diff --git a/packages/app/src/contexts/Pools/ActivePool/index.tsx b/packages/app/src/contexts/Pools/ActivePool/index.tsx
index ae5f69890..b95a0281d 100644
--- a/packages/app/src/contexts/Pools/ActivePool/index.tsx
+++ b/packages/app/src/contexts/Pools/ActivePool/index.tsx
@@ -16,6 +16,7 @@ import { defaultActivePoolContext, defaultPoolRoles } from './defaults';
import { SyncController } from 'controllers/Sync';
import { useActivePools } from 'hooks/useActivePools';
import BigNumber from 'bignumber.js';
+import { ApiController } from 'controllers/Api';
export const ActivePoolContext = createContext(
defaultActivePoolContext
@@ -187,10 +188,11 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
// Fetch and update unclaimed pool rewards for an address from runtime call.
const fetchPendingRewards = async (address: string | undefined) => {
- if (api && address) {
- const pendingRewards =
- await api.call.nominationPoolsApi.pendingRewards(address);
- return new BigNumber(pendingRewards?.toString() || 0);
+ const { pApi } = ApiController.get(network);
+ if (pApi && address) {
+ const apiResult =
+ await pApi.apis.NominationPoolsApi.pending_rewards(address);
+ return new BigNumber(apiResult?.toString() || 0);
}
return new BigNumber(0);
};
diff --git a/packages/app/src/contexts/WalletConnect/index.tsx b/packages/app/src/contexts/WalletConnect/index.tsx
index 8d0983a47..c67666d82 100644
--- a/packages/app/src/contexts/WalletConnect/index.tsx
+++ b/packages/app/src/contexts/WalletConnect/index.tsx
@@ -12,6 +12,7 @@ import { getSdkError } from '@walletconnect/utils';
import { getUnixTime } from 'date-fns';
import { useApi } from 'contexts/Api';
import { useNetwork } from 'contexts/Network';
+import { ApiController } from 'controllers/Api';
export const WalletConnectContext =
createContext(defaults.defaultWalletConnect);
@@ -27,10 +28,13 @@ export const WalletConnectProvider = ({
children: ReactNode;
}) => {
const { network } = useNetwork();
- const { isReady, api } = useApi();
+ const {
+ isReady,
+ chainSpecs: { genesisHash },
+ } = useApi();
// Check if the API is present.
- const apiPresent = api !== null;
+ const apiPresent = !!ApiController.get(network);
// The WalletConnect provider.
const wcProvider = useRef(null);
@@ -87,7 +91,7 @@ export const WalletConnectProvider = ({
// Connect WalletConnect provider and retrieve metadata.
const connectProvider = async () => {
- if (!wcInitialized || !api) {
+ if (!wcInitialized) {
return;
}
@@ -99,9 +103,7 @@ export const WalletConnectProvider = ({
// Update most recent connected chain.
sessionChain.current = network;
- const caips = [
- `polkadot:${api.genesisHash.toHex().substring(2).substring(0, 32)}`,
- ];
+ const caips = [`polkadot:${genesisHash.substring(2).substring(0, 32)}`];
// If there are no chains connected, return early.
if (!caips.length) {
@@ -159,15 +161,12 @@ export const WalletConnectProvider = ({
// Update session namespaces. NOTE: This method is currently not in use due to a
// default chain error upon reconnecting to the session.
const updateWcSession = async () => {
- if (!wcInitialized || !api) {
+ if (!wcInitialized) {
return;
}
// Update most recent connected chains.
sessionChain.current = network;
-
- const caips = [
- `polkadot:${api.genesisHash.toHex().substring(2).substring(0, 32)}`,
- ];
+ const caips = [`polkadot:${genesisHash.substring(2).substring(0, 32)}`];
// If there are no chains connected, return early.
if (!caips.length) {
@@ -279,9 +278,6 @@ export const WalletConnectProvider = ({
};
const fetchAddresses = async (): Promise => {
- if (!api) {
- return [];
- }
// Retrieve a new session or get current one.
const wcSession = await initializeWcSession();
if (wcSession === null) {
@@ -293,7 +289,7 @@ export const WalletConnectProvider = ({
.map((namespace: AnyJson) => namespace.accounts)
.flat();
- const caip = api.genesisHash.toHex().substring(2).substring(0, 32);
+ const caip = genesisHash.substring(2).substring(0, 32);
// Only get accounts for the currently selected `caip`.
let filteredAccounts = walletConnectAccounts.filter((wcAccount) => {
diff --git a/packages/app/src/hooks/useBatchCall/index.tsx b/packages/app/src/hooks/useBatchCall/index.tsx
index db4f281c7..1c882d47e 100644
--- a/packages/app/src/hooks/useBatchCall/index.tsx
+++ b/packages/app/src/hooks/useBatchCall/index.tsx
@@ -1,37 +1,46 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { useApi } from 'contexts/Api';
import type { AnyApi, MaybeAddress } from 'types';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
import { useProxySupported } from 'hooks/useProxySupported';
+import type { UnsafeTx } from 'hooks/useSubmitExtrinsic/types';
export const useBatchCall = () => {
- const { api } = useApi();
+ const { network } = useNetwork();
const { activeProxy } = useActiveAccounts();
const { isProxySupported } = useProxySupported();
- const newBatchCall = (txs: AnyApi[], from: MaybeAddress): AnyApi => {
- if (!api) {
+ const newBatchCall = (txs: UnsafeTx[], from: MaybeAddress): AnyApi => {
+ const { pApi } = ApiController.get(network);
+
+ if (!pApi) {
return undefined;
}
from = from || '';
+ const batchTx = pApi.tx.Utility.batch({
+ calls: txs.map((tx) => tx.decodedCall),
+ });
- if (activeProxy && isProxySupported(api.tx.utility.batch(txs), from)) {
- return api?.tx.utility.batch(
- txs.map((tx) =>
- api.tx.proxy.proxy(
- {
- id: from,
- },
- null,
- tx
- )
- )
- );
+ if (activeProxy && isProxySupported(batchTx, from)) {
+ return pApi.tx.Utility.batch({
+ calls: txs.map(
+ (tx) =>
+ pApi.tx.Proxy.proxy({
+ real: {
+ type: 'Id',
+ value: from,
+ },
+ force_proxy_type: null,
+ call: tx.decodedCall,
+ }).decodedCall
+ ),
+ });
}
- return api?.tx.utility.batch(txs);
+ return batchTx;
};
return {
diff --git a/packages/app/src/hooks/useBatchCallPapi/index.tsx b/packages/app/src/hooks/useBatchCallPapi/index.tsx
deleted file mode 100644
index 131e35f11..000000000
--- a/packages/app/src/hooks/useBatchCallPapi/index.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
-// SPDX-License-Identifier: GPL-3.0-only
-
-import type { AnyApi, MaybeAddress } from 'types';
-import { useActiveAccounts } from 'contexts/ActiveAccounts';
-import { ApiController } from 'controllers/Api';
-import { useNetwork } from 'contexts/Network';
-import { useProxySupportedPapi } from 'hooks/useProxySupportedPapi';
-import type { UnsafeTx } from 'hooks/useSubmitExtrinsicPapi/types';
-
-export const useBatchCallPapi = () => {
- const { network } = useNetwork();
- const { activeProxy } = useActiveAccounts();
- const { isProxySupported } = useProxySupportedPapi();
-
- const newBatchCall = (txs: UnsafeTx[], from: MaybeAddress): AnyApi => {
- const { pApi } = ApiController.get(network);
-
- if (!pApi) {
- return undefined;
- }
-
- from = from || '';
- const batchTx = pApi.tx.Utility.batch({
- calls: txs.map((tx) => tx.decodedCall),
- });
-
- if (activeProxy && isProxySupported(batchTx, from)) {
- return pApi.tx.Utility.batch({
- calls: txs.map(
- (tx) =>
- pApi.tx.Proxy.proxy({
- real: {
- type: 'Id',
- value: from,
- },
- force_proxy_type: null,
- call: tx.decodedCall,
- }).decodedCall
- ),
- });
- }
- return batchTx;
- };
-
- return {
- newBatchCall,
- };
-};
diff --git a/packages/app/src/hooks/useBondGreatestFee/index.tsx b/packages/app/src/hooks/useBondGreatestFee/index.tsx
index 651cc451a..d343e3e95 100644
--- a/packages/app/src/hooks/useBondGreatestFee/index.tsx
+++ b/packages/app/src/hooks/useBondGreatestFee/index.tsx
@@ -48,11 +48,13 @@ export const useBondGreatestFee = ({ bondFor }: { bondFor: BondFor }) => {
}
if (bondFor === 'pool') {
tx = pApi.tx.NominationPools.bond_extra({
- type: 'FreeBalance',
- value: BigInt(bond),
+ extra: {
+ type: 'FreeBalance',
+ value: BigInt(bond),
+ },
});
} else if (bondFor === 'nominator') {
- tx = pApi.tx.Staking.bond_extra({ bond });
+ tx = pApi.tx.Staking.bond_extra({ max_additional: BigInt(bond) });
}
if (tx) {
diff --git a/packages/app/src/hooks/useBuildPayload/index.tsx b/packages/app/src/hooks/useBuildPayload/index.tsx
deleted file mode 100644
index dba77380f..000000000
--- a/packages/app/src/hooks/useBuildPayload/index.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
-// SPDX-License-Identifier: GPL-3.0-only
-
-import { merkleizeMetadata } from '@polkadot-api/merkleize-metadata';
-import type { ApiPromise } from '@polkadot/api';
-import { u8aToHex, objectSpread } from '@polkadot/util';
-import type { AnyJson } from '@w3ux/types';
-import { useApi } from 'contexts/Api';
-import { useBalances } from 'contexts/Balances';
-import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
-import { useTxMeta } from 'contexts/TxMeta';
-import type { AnyApi } from 'types';
-
-export const useBuildPayload = () => {
- const { api } = useApi();
- const { getNonce } = useBalances();
- const { setTxPayload } = useTxMeta();
- const { getAccount } = useImportedAccounts();
-
- // Build metadata hash and return updated payload.
- const fetchMetadataHash = async (a: ApiPromise, p: AnyJson) => {
- const metadata = await a.call.metadata.metadataAtVersion(15);
- const { specName, specVersion } = a.runtimeVersion;
-
- const opts = {
- base58Prefix: Number(a.consts.system.ss58Prefix.toString()),
- decimals: a.registry.chainDecimals[0],
- specName: specName.toString(),
- specVersion: specVersion.toNumber(),
- tokenSymbol: a.registry.chainTokens[0],
- };
-
- const merkleizedMetadata = merkleizeMetadata(metadata.toHex(), opts);
- const metadataHash = u8aToHex(merkleizedMetadata.digest());
- const payload = objectSpread({}, p, {
- metadataHash,
- mode: 1,
- withSignedTransaction: true,
- });
- const newPayload = a.registry.createType('ExtrinsicPayload', payload);
-
- return {
- newPayload,
- newTxMetadata: merkleizedMetadata.getProofForExtrinsicPayload(
- u8aToHex(newPayload.toU8a(true))
- ),
- };
- };
-
- // Build and set payload of the transaction and store it in TxMetaContext.
- const buildPayload = async (tx: AnyApi, from: string, uid: number) => {
- if (api && tx) {
- const accountMeta = getAccount(from);
- const source = accountMeta?.source;
-
- const lastHeader = await api.rpc.chain.getHeader();
- const blockNumber = api.registry.createType(
- 'BlockNumber',
- lastHeader.number.toNumber()
- );
- const method = api.createType('Call', tx);
- const era = api.registry.createType('ExtrinsicEra', {
- current: lastHeader.number.toNumber(),
- period: 64,
- });
-
- const accountNonce = getNonce(from);
- const nonce = api.registry.createType('Compact', accountNonce);
-
- // Construct the payload value.
- const payloadJson: AnyJson = {
- specVersion: api.runtimeVersion.specVersion.toHex(),
- transactionVersion: api.runtimeVersion.transactionVersion.toHex(),
- runtimeVersion: api.runtimeVersion,
- version: api.extrinsicVersion,
- address: from,
- blockHash: lastHeader.hash.toHex(),
- blockNumber: blockNumber.toHex(),
- era: era.toHex(),
- genesisHash: api.genesisHash.toHex(),
- method: method.toHex(),
- nonce: nonce.toHex(),
- signedExtensions: api.registry.signedExtensions,
- tip: api.registry.createType('Compact', 0).toHex(),
- };
-
- let payload;
- let txMetadata = null;
-
- // If the source is `ledger`, add the metadata hash to the payload.
- if (source === 'ledger') {
- const { newPayload, newTxMetadata } = await fetchMetadataHash(
- api,
- payloadJson
- );
- payload = newPayload;
- txMetadata = newTxMetadata;
- } else {
- // Create the payload raw.
- payload = api.registry.createType('ExtrinsicPayload', payloadJson, {
- version: payloadJson.version,
- });
- }
-
- // Persist both the payload and the payload bytes in state, indexed by its uid.
- setTxPayload(txMetadata, payload, payloadJson, uid);
- }
- };
-
- return {
- buildPayload,
- };
-};
diff --git a/packages/app/src/hooks/useProxySupported/index.tsx b/packages/app/src/hooks/useProxySupported/index.tsx
index d45ebf232..7fea61584 100644
--- a/packages/app/src/hooks/useProxySupported/index.tsx
+++ b/packages/app/src/hooks/useProxySupported/index.tsx
@@ -8,8 +8,9 @@ import {
import { useBonded } from 'contexts/Bonded';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { useProxies } from 'contexts/Proxies';
-import type { AnyApi, MaybeAddress } from 'types';
+import type { MaybeAddress } from 'types';
import type { AnyJson } from '@w3ux/types';
+import type { UnsafeTx } from 'hooks/useSubmitExtrinsic/types';
export const useProxySupported = () => {
const { getBondedAccount } = useBonded();
@@ -22,32 +23,32 @@ export const useProxySupported = () => {
UnsupportedIfUniqueController.includes(c) && getBondedAccount(f) !== f;
// Determine whether the provided tx is proxy supported.
- const isProxySupported = (tx: AnyApi, delegator: MaybeAddress) => {
+ const isProxySupported = (tx: UnsafeTx, delegator: MaybeAddress) => {
// if already wrapped, return.
if (
- tx?.method.toHuman().section === 'proxy' &&
- tx?.method.toHuman().method === 'proxy'
+ tx?.decodedCall.type === 'Proxy' &&
+ tx?.decodedCall.value.type === 'proxy'
) {
return true;
}
const proxyDelegate = getProxyDelegate(delegator, activeProxy);
const proxyType = proxyDelegate?.proxyType || '';
- const pallet = tx?.method.toHuman().section;
- const method = tx?.method.toHuman().method;
+ const pallet: string = (tx?.decodedCall.type || '').toLowerCase();
+ const method: string = (tx?.decodedCall.value.type || '').toLowerCase();
const call = `${pallet}.${method}`;
// If a batch call, test if every inner call is a supported proxy call.
if (call === 'utility.batch') {
- return (tx?.method?.toHuman()?.args?.calls || [])
+ return (tx?.decodedCall.value?.value?.calls || [])
.map((c: AnyJson) => ({
- pallet: c.section,
- method: c.method,
+ pallet: c.type,
+ method: c.value.type,
}))
.every(
(c: AnyJson) =>
(isSupportedProxyCall(proxyType, c.pallet, c.method) ||
- (c.pallet === 'proxy' && c.method === 'proxy')) &&
+ (c.pallet === 'Proxy' && c.method === 'proxy')) &&
!controllerNotSupported(`${pallet}.${method}`, delegator)
);
}
diff --git a/packages/app/src/hooks/useProxySupportedPapi/index.tsx b/packages/app/src/hooks/useProxySupportedPapi/index.tsx
deleted file mode 100644
index 0c3e12a6c..000000000
--- a/packages/app/src/hooks/useProxySupportedPapi/index.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
-// SPDX-License-Identifier: GPL-3.0-only
-
-import {
- UnsupportedIfUniqueController,
- isSupportedProxyCall,
-} from 'config/proxies';
-import { useBonded } from 'contexts/Bonded';
-import { useActiveAccounts } from 'contexts/ActiveAccounts';
-import { useProxies } from 'contexts/Proxies';
-import type { MaybeAddress } from 'types';
-import type { AnyJson } from '@w3ux/types';
-import type { UnsafeTx } from 'hooks/useSubmitExtrinsicPapi/types';
-
-export const useProxySupportedPapi = () => {
- const { getBondedAccount } = useBonded();
- const { getProxyDelegate } = useProxies();
- const { activeProxy } = useActiveAccounts();
-
- // If call is from controller, & controller is different from stash, then proxy is not
- // supported.
- const controllerNotSupported = (c: string, f: MaybeAddress) =>
- UnsupportedIfUniqueController.includes(c) && getBondedAccount(f) !== f;
-
- // Determine whether the provided tx is proxy supported.
- const isProxySupported = (tx: UnsafeTx, delegator: MaybeAddress) => {
- // if already wrapped, return.
- if (
- tx?.decodedCall.type === 'Proxy' &&
- tx?.decodedCall.value.type === 'proxy'
- ) {
- return true;
- }
-
- const proxyDelegate = getProxyDelegate(delegator, activeProxy);
- const proxyType = proxyDelegate?.proxyType || '';
- const pallet: string = (tx?.decodedCall.type || '').toLowerCase();
- const method: string = (tx?.decodedCall.value.type || '').toLowerCase();
- const call = `${pallet}.${method}`;
-
- // If a batch call, test if every inner call is a supported proxy call.
- if (call === 'utility.batch') {
- return (tx?.decodedCall.value?.value?.calls || [])
- .map((c: AnyJson) => ({
- pallet: c.type,
- method: c.value.type,
- }))
- .every(
- (c: AnyJson) =>
- (isSupportedProxyCall(proxyType, c.pallet, c.method) ||
- (c.pallet === 'Proxy' && c.method === 'proxy')) &&
- !controllerNotSupported(`${pallet}.${method}`, delegator)
- );
- }
-
- // Check if the current call is a supported proxy call.
- return (
- isSupportedProxyCall(proxyType, pallet, method) &&
- !controllerNotSupported(call, delegator)
- );
- };
-
- return {
- isProxySupported,
- };
-};
diff --git a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
index 4b969a395..b413b04ad 100644
--- a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
+++ b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
@@ -5,17 +5,24 @@ import BigNumber from 'bignumber.js';
import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { DappName, ManualSigners } from 'consts';
-import { useApi } from 'contexts/Api';
import { useLedgerHardware } from 'contexts/LedgerHardware';
import { useTxMeta } from 'contexts/TxMeta';
-import type { AnyApi } from 'types';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
-import { useBuildPayload } from '../useBuildPayload';
-import { useProxySupported } from '../useProxySupported';
-import type { UseSubmitExtrinsic, UseSubmitExtrinsicProps } from './types';
+import type {
+ UnsafeTx,
+ UseSubmitExtrinsic,
+ UseSubmitExtrinsicProps,
+} from './types';
import { NotificationsController } from 'controllers/Notifications';
import { useExtensions } from '@w3ux/react-connect-kit';
+import { useProxySupported } from 'hooks/useProxySupported';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useBalances } from 'contexts/Balances';
+import { InvalidTxError } from 'polkadot-api';
+import { connectInjectedExtension } from 'polkadot-api/pjs-signer';
+import { formatAccountSs58 } from '@w3ux/utils';
export const useSubmitExtrinsic = ({
tx,
@@ -25,27 +32,18 @@ export const useSubmitExtrinsic = ({
callbackInBlock,
}: UseSubmitExtrinsicProps): UseSubmitExtrinsic => {
const { t } = useTranslation('library');
- const { api } = useApi();
- const { buildPayload } = useBuildPayload();
+ const { network } = useNetwork();
+ const { getNonce } = useBalances();
const { activeProxy } = useActiveAccounts();
const { extensionsStatus } = useExtensions();
const { isProxySupported } = useProxySupported();
const { handleResetLedgerTask } = useLedgerHardware();
const { addPendingNonce, removePendingNonce } = useTxMeta();
const { getAccount, requiresManualSign } = useImportedAccounts();
- const {
- txFees,
- setTxFees,
- setSender,
- getTxPayload,
- getTxSignature,
- setTxSignature,
- resetTxPayload,
- incrementPayloadUid,
- } = useTxMeta();
+ const { txFees, setTxFees, setSender, incrementPayloadUid } = useTxMeta();
// Store given tx as a ref.
- const txRef = useRef(tx);
+ const txRef = useRef(tx);
// Store given submit address as a ref.
const fromRef = useRef(from || '');
@@ -61,10 +59,12 @@ export const useSubmitExtrinsic = ({
// If proxy account is active, wrap tx in a proxy call and set the sender to the proxy account.
const wrapTxIfActiveProxy = () => {
+ const { pApi } = ApiController.get(network);
+
// if already wrapped, update fromRef and return.
if (
- txRef.current?.method.toHuman().section === 'proxy' &&
- txRef.current?.method.toHuman().method === 'proxy'
+ txRef.current?.decodedCall.type === 'Proxy' &&
+ txRef.current?.decodedCall.value.type === 'proxy'
) {
if (activeProxy) {
fromRef.current = activeProxy;
@@ -73,7 +73,7 @@ export const useSubmitExtrinsic = ({
}
if (
- api &&
+ pApi &&
activeProxy &&
txRef.current &&
isProxySupported(txRef.current, fromRef.current)
@@ -84,20 +84,21 @@ export const useSubmitExtrinsic = ({
// Do not wrap batch transactions. Proxy calls should already be wrapping each tx within the
// batch via `useBatchCall`.
if (
- txRef.current?.method.toHuman().section === 'utility' &&
- txRef.current?.method.toHuman().method === 'batch'
+ txRef.current?.decodedCall.type === 'Utility' &&
+ txRef.current?.decodedCall.value.type === 'batch'
) {
return;
}
// Not a batch transaction: wrap tx in proxy call.
- txRef.current = api.tx.proxy.proxy(
- {
- id: from,
+ txRef.current = pApi.tx.Proxy.proxy({
+ real: {
+ type: 'Id',
+ value: from,
},
- null,
- txRef.current
- );
+ forceProxyType: null,
+ call: txRef.current.decodedCall,
+ });
}
};
@@ -106,8 +107,10 @@ export const useSubmitExtrinsic = ({
if (txRef.current === null) {
return;
}
+
// get payment info
- const { partialFee } = await txRef.current.paymentInfo(fromRef.current);
+ const partialFee = (await txRef.current.getPaymentInfo(fromRef.current))
+ .partial_fee;
const partialFeeBn = new BigNumber(partialFee.toString());
// give tx fees to global useTxMeta context
@@ -119,24 +122,16 @@ export const useSubmitExtrinsic = ({
// Extrinsic submission handler.
const onSubmit = async () => {
const account = getAccount(fromRef.current);
- if (
- account === null ||
- submitting ||
- !shouldSubmit ||
- !api ||
- (requiresManualSign(fromRef.current) && !getTxSignature())
- ) {
+ if (account === null || submitting || !shouldSubmit) {
return;
}
- const nonce = (
- await api.rpc.system.accountNextIndex(fromRef.current)
- ).toHuman();
-
+ const nonce = String(getNonce(fromRef.current));
const { source } = account;
+ const isManualSigner = ManualSigners.includes(source);
// if `activeAccount` is imported from an extension, ensure it is enabled.
- if (!ManualSigners.includes(source)) {
+ if (!isManualSigner) {
const isInstalled = Object.entries(extensionsStatus).find(
([id, status]) => id === source && status === 'connected'
);
@@ -176,31 +171,26 @@ export const useSubmitExtrinsic = ({
}
};
- const onFinalizedEvent = (method: string) => {
- if (method === 'ExtrinsicSuccess') {
- NotificationsController.emit({
- title: t('finalized'),
- subtitle: t('transactionSuccessful'),
- });
- } else if (method === 'ExtrinsicFailed') {
- NotificationsController.emit({
- title: t('failed'),
- subtitle: t('errorWithTransaction'),
- });
- setSubmitting(false);
- removePendingNonce(nonce);
- }
+ const onFinalizedEvent = () => {
+ NotificationsController.emit({
+ title: t('finalized'),
+ subtitle: t('transactionSuccessful'),
+ });
+ setSubmitting(false);
+ removePendingNonce(nonce);
};
- const resetTx = () => {
- resetTxPayload();
- setTxSignature(null);
+ const onFailedTx = () => {
+ NotificationsController.emit({
+ title: t('failed'),
+ subtitle: t('errorWithTransaction'),
+ });
setSubmitting(false);
+ removePendingNonce(nonce);
};
- const resetManualTx = () => {
- resetTx();
- handleResetLedgerTask();
+ const resetTx = () => {
+ setSubmitting(false);
};
const onError = (type?: string) => {
@@ -215,80 +205,55 @@ export const useSubmitExtrinsic = ({
});
};
- const handleStatus = (status: AnyApi) => {
- if (status.isReady) {
+ const handleStatus = (status: string) => {
+ if (status === 'broadcasted') {
onReady();
}
- if (status.isInBlock) {
+ if (status === 'txBestBlocksState') {
onInBlock();
}
};
- const unsubEvents = ['ExtrinsicSuccess', 'ExtrinsicFailed'];
-
// pre-submission state update
setSubmitting(true);
- const txPayloadValue = getTxPayload();
- const txSignature = getTxSignature();
-
// handle signed transaction.
- if (getTxSignature()) {
- try {
- txRef.current.addSignature(
- fromRef.current,
- txSignature,
- txPayloadValue.toHex()
- );
-
- const unsub = await txRef.current.send(
- ({ status, events = [] }: AnyApi) => {
- if (!didTxReset.current) {
- didTxReset.current = true;
- resetManualTx();
- }
-
- handleStatus(status);
- if (status.isFinalized) {
- events.forEach(({ event: { method } }: AnyApi) => {
- onFinalizedEvent(method);
- if (unsubEvents?.includes(method)) {
- unsub();
- }
- });
- }
- }
- );
- } catch (e) {
- onError(ManualSigners.includes(source) ? source : 'default');
- }
+ let signer;
+ if (requiresManualSign(fromRef.current)) {
+ // TODO: Get custom signer here.
} else {
- // handle unsigned transaction.
- const { signer } = account;
- try {
- const unsub = await txRef.current.signAndSend(
- fromRef.current,
- { signer, withSignedTransaction: true },
- ({ status, events = [] }: AnyApi) => {
- if (!didTxReset.current) {
- didTxReset.current = true;
- resetTx();
- }
-
- handleStatus(status);
- if (status.isFinalized) {
- events.forEach(({ event: { method } }: AnyApi) => {
- onFinalizedEvent(method);
- if (unsubEvents?.includes(method)) {
- unsub();
- }
- });
- }
+ // Get the polkadot signer for this account.
+ signer = (await connectInjectedExtension(source))
+ .getAccounts()
+ .find(
+ (a) => a.address === formatAccountSs58(fromRef.current, 42)
+ )?.polkadotSigner;
+ }
+
+ try {
+ const sub = tx.signSubmitAndWatch(signer).subscribe({
+ next: (result: { type: string }) => {
+ const eventType = result?.type;
+
+ if (!didTxReset.current) {
+ didTxReset.current = true;
+ resetTx();
}
- );
- } catch (e) {
- onError('default');
- }
+ handleStatus(eventType);
+ if (eventType === 'finalized') {
+ onFinalizedEvent();
+ sub?.unsubscribe();
+ }
+ },
+ error: (err: Error) => {
+ if (err instanceof InvalidTxError) {
+ onFailedTx();
+ }
+ sub?.unsubscribe();
+ },
+ });
+ } catch (e) {
+ onError('default');
}
};
@@ -304,8 +269,6 @@ export const useSubmitExtrinsic = ({
setSender(fromRef.current);
// re-calculate estimated tx fee.
calculateEstimatedFee();
- // rebuild tx payload.
- buildPayload(txRef.current, fromRef.current, uid);
}, [tx?.toString(), tx?.method?.args?.calls?.toString(), from]);
return {
diff --git a/packages/app/src/hooks/useSubmitExtrinsic/types.ts b/packages/app/src/hooks/useSubmitExtrinsic/types.ts
index 5eb2febf3..292c83817 100644
--- a/packages/app/src/hooks/useSubmitExtrinsic/types.ts
+++ b/packages/app/src/hooks/useSubmitExtrinsic/types.ts
@@ -1,6 +1,7 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
+import type { UnsafeTransaction } from 'polkadot-api';
import type { AnyApi, MaybeAddress } from 'types';
export interface UseSubmitExtrinsicProps {
@@ -18,3 +19,6 @@ export interface UseSubmitExtrinsic {
proxySupported: boolean;
submitAddress: MaybeAddress;
}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type UnsafeTx = UnsafeTransaction;
diff --git a/packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx b/packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx
deleted file mode 100644
index 517f9c062..000000000
--- a/packages/app/src/hooks/useSubmitExtrinsicPapi/index.tsx
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
-// SPDX-License-Identifier: GPL-3.0-only
-
-import BigNumber from 'bignumber.js';
-import { useEffect, useRef, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { DappName, ManualSigners } from 'consts';
-import { useLedgerHardware } from 'contexts/LedgerHardware';
-import { useTxMeta } from 'contexts/TxMeta';
-import { useActiveAccounts } from 'contexts/ActiveAccounts';
-import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
-import type {
- UnsafeTx,
- UseSubmitExtrinsic,
- UseSubmitExtrinsicProps,
-} from './types';
-import { NotificationsController } from 'controllers/Notifications';
-import { useExtensions } from '@w3ux/react-connect-kit';
-import { useProxySupportedPapi } from 'hooks/useProxySupportedPapi';
-import { ApiController } from 'controllers/Api';
-import { useNetwork } from 'contexts/Network';
-import { useBalances } from 'contexts/Balances';
-import { InvalidTxError } from 'polkadot-api';
-import { connectInjectedExtension } from 'polkadot-api/pjs-signer';
-import { formatAccountSs58 } from '@w3ux/utils';
-
-export const useSubmitExtrinsicPapi = ({
- tx,
- from,
- shouldSubmit,
- callbackSubmit,
- callbackInBlock,
-}: UseSubmitExtrinsicProps): UseSubmitExtrinsic => {
- const { t } = useTranslation('library');
- const { network } = useNetwork();
- const { getNonce } = useBalances();
- const { activeProxy } = useActiveAccounts();
- const { extensionsStatus } = useExtensions();
- const { isProxySupported } = useProxySupportedPapi();
- const { handleResetLedgerTask } = useLedgerHardware();
- const { addPendingNonce, removePendingNonce } = useTxMeta();
- const { getAccount, requiresManualSign } = useImportedAccounts();
- const { txFees, setTxFees, setSender, incrementPayloadUid } = useTxMeta();
-
- // Store given tx as a ref.
- const txRef = useRef(tx);
-
- // Store given submit address as a ref.
- const fromRef = useRef(from || '');
-
- // Store whether the transaction is in progress.
- const [submitting, setSubmitting] = useState(false);
-
- // Store the uid of the extrinsic.
- const [uid] = useState(incrementPayloadUid());
-
- // Track for one-shot transaction reset after submission.
- const didTxReset = useRef(false);
-
- // If proxy account is active, wrap tx in a proxy call and set the sender to the proxy account.
- const wrapTxIfActiveProxy = () => {
- const { pApi } = ApiController.get(network);
-
- // if already wrapped, update fromRef and return.
- if (
- txRef.current?.decodedCall.type === 'Proxy' &&
- txRef.current?.decodedCall.value.type === 'proxy'
- ) {
- if (activeProxy) {
- fromRef.current = activeProxy;
- }
- return;
- }
-
- if (
- pApi &&
- activeProxy &&
- txRef.current &&
- isProxySupported(txRef.current, fromRef.current)
- ) {
- // update submit address to active proxy account.
- fromRef.current = activeProxy;
-
- // Do not wrap batch transactions. Proxy calls should already be wrapping each tx within the
- // batch via `useBatchCall`.
- if (
- txRef.current?.decodedCall.type === 'Utility' &&
- txRef.current?.decodedCall.value.type === 'batch'
- ) {
- return;
- }
-
- // Not a batch transaction: wrap tx in proxy call.
- txRef.current = pApi.tx.Proxy.proxy({
- real: {
- type: 'Id',
- value: from,
- },
- forceProxyType: null,
- call: txRef.current.decodedCall,
- });
- }
- };
-
- // Calculate the estimated tx fee of the transaction.
- const calculateEstimatedFee = async () => {
- if (txRef.current === null) {
- return;
- }
-
- // get payment info
- const partialFee = (await txRef.current.getPaymentInfo(fromRef.current))
- .partial_fee;
- const partialFeeBn = new BigNumber(partialFee.toString());
-
- // give tx fees to global useTxMeta context
- if (partialFeeBn.toString() !== txFees.toString()) {
- setTxFees(partialFeeBn);
- }
- };
-
- // Extrinsic submission handler.
- const onSubmit = async () => {
- const account = getAccount(fromRef.current);
- if (account === null || submitting || !shouldSubmit) {
- return;
- }
-
- const nonce = String(getNonce(fromRef.current));
- const { source } = account;
- const isManualSigner = ManualSigners.includes(source);
-
- // if `activeAccount` is imported from an extension, ensure it is enabled.
- if (!isManualSigner) {
- const isInstalled = Object.entries(extensionsStatus).find(
- ([id, status]) => id === source && status === 'connected'
- );
-
- if (!isInstalled) {
- throw new Error(`${t('walletNotFound')}`);
- }
-
- if (!window?.injectedWeb3?.[source]) {
- throw new Error(`${t('walletNotFound')}`);
- }
-
- // summons extension popup if not already connected.
- window.injectedWeb3[source].enable(DappName);
- }
-
- const onReady = () => {
- addPendingNonce(nonce);
- NotificationsController.emit({
- title: t('pending'),
- subtitle: t('transactionInitiated'),
- });
- if (callbackSubmit && typeof callbackSubmit === 'function') {
- callbackSubmit();
- }
- };
-
- const onInBlock = () => {
- setSubmitting(false);
- removePendingNonce(nonce);
- NotificationsController.emit({
- title: t('inBlock'),
- subtitle: t('transactionInBlock'),
- });
- if (callbackInBlock && typeof callbackInBlock === 'function') {
- callbackInBlock();
- }
- };
-
- const onFinalizedEvent = () => {
- NotificationsController.emit({
- title: t('finalized'),
- subtitle: t('transactionSuccessful'),
- });
- setSubmitting(false);
- removePendingNonce(nonce);
- };
-
- const onFailedTx = () => {
- NotificationsController.emit({
- title: t('failed'),
- subtitle: t('errorWithTransaction'),
- });
- setSubmitting(false);
- removePendingNonce(nonce);
- };
-
- const resetTx = () => {
- setSubmitting(false);
- };
-
- const onError = (type?: string) => {
- resetTx();
- if (type === 'ledger') {
- handleResetLedgerTask();
- }
- removePendingNonce(nonce);
- NotificationsController.emit({
- title: t('cancelled'),
- subtitle: t('transactionCancelled'),
- });
- };
-
- const handleStatus = (status: string) => {
- if (status === 'broadcasted') {
- onReady();
- }
- if (status === 'txBestBlocksState') {
- onInBlock();
- }
- };
-
- // pre-submission state update
- setSubmitting(true);
-
- // handle signed transaction.
- let signer;
- if (requiresManualSign(fromRef.current)) {
- // TODO: Get custom signer here.
- } else {
- // Get the polkadot signer for this account.
- signer = (await connectInjectedExtension(source))
- .getAccounts()
- .find(
- (a) => a.address === formatAccountSs58(fromRef.current, 42)
- )?.polkadotSigner;
- }
-
- try {
- const sub = tx.signSubmitAndWatch(signer).subscribe({
- next: (result: { type: string }) => {
- const eventType = result?.type;
-
- if (!didTxReset.current) {
- didTxReset.current = true;
- resetTx();
- }
- handleStatus(eventType);
- if (eventType === 'finalized') {
- onFinalizedEvent();
- sub?.unsubscribe();
- }
- },
- error: (err: Error) => {
- if (err instanceof InvalidTxError) {
- onFailedTx();
- }
- sub?.unsubscribe();
- },
- });
- } catch (e) {
- onError('default');
- }
- };
-
- // Refresh state upon `tx` updates.
- useEffect(() => {
- // update txRef to latest tx.
- txRef.current = tx;
- // update submit address to latest from.
- fromRef.current = from || '';
- // wrap tx in proxy call if active proxy & proxy supported.
- wrapTxIfActiveProxy();
- // ensure sender is up to date.
- setSender(fromRef.current);
- // re-calculate estimated tx fee.
- calculateEstimatedFee();
- }, [tx?.toString(), tx?.method?.args?.calls?.toString(), from]);
-
- return {
- uid,
- onSubmit,
- submitting,
- submitAddress: fromRef.current,
- proxySupported: isProxySupported(txRef.current, fromRef.current),
- };
-};
diff --git a/packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts b/packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts
deleted file mode 100644
index 292c83817..000000000
--- a/packages/app/src/hooks/useSubmitExtrinsicPapi/types.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
-// SPDX-License-Identifier: GPL-3.0-only
-
-import type { UnsafeTransaction } from 'polkadot-api';
-import type { AnyApi, MaybeAddress } from 'types';
-
-export interface UseSubmitExtrinsicProps {
- tx: AnyApi;
- from: MaybeAddress;
- shouldSubmit: boolean;
- callbackSubmit?: () => void;
- callbackInBlock?: () => void;
-}
-
-export interface UseSubmitExtrinsic {
- uid: number;
- onSubmit: () => void;
- submitting: boolean;
- proxySupported: boolean;
- submitAddress: MaybeAddress;
-}
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export type UnsafeTx = UnsafeTransaction;
diff --git a/packages/app/src/library/SubmitTx/ManualSign/WalletConnect/index.tsx b/packages/app/src/library/SubmitTx/ManualSign/WalletConnect/index.tsx
index 7644260c4..b1dbdc57d 100644
--- a/packages/app/src/library/SubmitTx/ManualSign/WalletConnect/index.tsx
+++ b/packages/app/src/library/SubmitTx/ManualSign/WalletConnect/index.tsx
@@ -24,7 +24,9 @@ export const WalletConnect = ({
displayFor,
}: SubmitProps & { buttons?: ReactNode[] }) => {
const { t } = useTranslation('library');
- const { api } = useApi();
+ const {
+ chainSpecs: { genesisHash },
+ } = useApi();
const { accountHasSigner } = useImportedAccounts();
const { wcSessionActive, connectProvider, fetchAddresses, signWcTx } =
useWalletConnect();
@@ -49,10 +51,6 @@ export const WalletConnect = ({
buttonPulse = valid;
} else {
buttonOnClick = async () => {
- if (!api) {
- return;
- }
-
// If Wallet Connect session is not active, re-connect.
if (!wcSessionActive) {
await connectProvider();
@@ -68,7 +66,7 @@ export const WalletConnect = ({
setIsSigning(true);
- const caip = `polkadot:${api.genesisHash.toHex().substring(2).substring(0, 32)}`;
+ const caip = `polkadot:${genesisHash.substring(2).substring(0, 32)}`;
try {
const signature = await signWcTx(caip, payload, sender);
diff --git a/packages/app/src/modals/Bond/index.tsx b/packages/app/src/modals/Bond/index.tsx
index 6dae88fc7..560d12356 100644
--- a/packages/app/src/modals/Bond/index.tsx
+++ b/packages/app/src/modals/Bond/index.tsx
@@ -5,14 +5,12 @@ import { unitToPlanck } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { useTransferOptions } from 'contexts/TransferOptions';
import { BondFeedback } from 'library/Form/Bond/BondFeedback';
import { Warning } from 'library/Form/Warning';
import { useBondGreatestFee } from 'hooks/useBondGreatestFee';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Close } from 'library/Modal/Close';
import { SubmitTx } from 'library/SubmitTx';
import { useTxMeta } from 'contexts/TxMeta';
@@ -22,11 +20,13 @@ import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { planckToUnitBn } from 'library/Utils';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const Bond = () => {
const { t } = useTranslation('modals');
- const { api } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { notEnoughFunds } = useTxMeta();
@@ -95,8 +95,9 @@ export const Bond = () => {
// determine whether this is a pool or staking transaction.
const determineTx = (bondToSubmit: BigNumber) => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!api) {
+ if (!pApi) {
return tx;
}
@@ -107,18 +108,21 @@ export const Bond = () => {
: bondToSubmit.toString();
if (isPooling) {
- tx = api.tx.nominationPools.bondExtra({
- FreeBalance: bondAsString,
+ tx = pApi.tx.NominationPools.bond_extra({
+ extra: {
+ type: 'FreeBalance',
+ value: bondAsString,
+ },
});
} else if (isStaking) {
- tx = api.tx.staking.bondExtra(bondAsString);
+ tx = pApi.tx.Staking.bond_extra({ max_additional: BigInt(bondAsString) });
}
return tx;
};
// the actual bond tx to submit
const getTx = (bondToSubmit: BigNumber) => {
- if (!api || !activeAccount) {
+ if (!activeAccount) {
return null;
}
return determineTx(bondToSubmit);
diff --git a/packages/app/src/modals/ClaimPayouts/Forms.tsx b/packages/app/src/modals/ClaimPayouts/Forms.tsx
index a95be27d3..db5ad9cfc 100644
--- a/packages/app/src/modals/ClaimPayouts/Forms.tsx
+++ b/packages/app/src/modals/ClaimPayouts/Forms.tsx
@@ -7,13 +7,10 @@ import BigNumber from 'bignumber.js';
import type { ForwardedRef } from 'react';
import { forwardRef, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import { useOverlay } from 'kits/Overlay/Provider';
-import { useBatchCall } from 'hooks/useBatchCall';
import type { AnyApi } from 'types';
import { usePayouts } from 'contexts/Payouts';
import { useNetwork } from 'contexts/Network';
@@ -25,6 +22,9 @@ import { ButtonSubmitInvert } from 'ui-buttons';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
+import { ApiController } from 'controllers/Api';
+import { useBatchCall } from 'hooks/useBatchCall';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const Forms = forwardRef(
(
@@ -32,8 +32,8 @@ export const Forms = forwardRef(
ref: ForwardedRef
) => {
const { t } = useTranslation('modals');
- const { api } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { newBatchCall } = useBatchCall();
@@ -59,7 +59,8 @@ export const Forms = forwardRef(
) || 0;
const getCalls = () => {
- if (!api) {
+ const { pApi } = ApiController.get(network);
+ if (!pApi) {
return [];
}
@@ -69,7 +70,13 @@ export const Forms = forwardRef(
return [];
}
return paginatedValidators.forEach(([page, v]) =>
- calls.push(api.tx.staking.payoutStakersByPage(v, era, page))
+ calls.push(
+ pApi.tx.Staking.payout_stakers_by_page({
+ validator_stash: v,
+ era: Number(era),
+ page,
+ })
+ )
);
});
return calls;
@@ -89,7 +96,7 @@ export const Forms = forwardRef(
const getTx = () => {
const tx = null;
const calls = getCalls();
- if (!valid || !api || !calls.length) {
+ if (!valid || !calls.length) {
return tx;
}
diff --git a/packages/app/src/modals/ClaimReward/index.tsx b/packages/app/src/modals/ClaimReward/index.tsx
index 7c8ec608c..c59eceaa4 100644
--- a/packages/app/src/modals/ClaimReward/index.tsx
+++ b/packages/app/src/modals/ClaimReward/index.tsx
@@ -3,11 +3,9 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Close } from 'library/Modal/Close';
import { SubmitTx } from 'library/SubmitTx';
import { useTxMeta } from 'contexts/TxMeta';
@@ -18,23 +16,24 @@ import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
import { planckToUnit } from '@w3ux/utils';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const ClaimReward = () => {
const { t } = useTranslation('modals');
- const { api } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
- const { notEnoughFunds } = useTxMeta();
- const { activeAccount } = useActiveAccounts();
- const { getSignerWarnings } = useSignerWarnings();
- const { activePool, pendingPoolRewards } = useActivePool();
const {
setModalStatus,
config: { options },
setModalResize,
} = useOverlay().modal;
-
+ const { notEnoughFunds } = useTxMeta();
+ const { activeAccount } = useActiveAccounts();
+ const { getSignerWarnings } = useSignerWarnings();
+ const { activePool, pendingPoolRewards } = useActivePool();
const { claimType } = options;
// ensure selected payout is valid
@@ -51,15 +50,16 @@ export const ClaimReward = () => {
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!api) {
+ if (!pApi) {
return tx;
}
if (claimType === 'bond') {
- tx = api.tx.nominationPools.bondExtra('Rewards');
+ tx = pApi.tx.NominationPools.bond_extra({ extra: { type: 'Rewards' } });
} else {
- tx = api.tx.nominationPools.claimPayout();
+ tx = pApi.tx.NominationPools.claim_payout();
}
return tx;
};
diff --git a/packages/app/src/modals/ManageFastUnstake/index.tsx b/packages/app/src/modals/ManageFastUnstake/index.tsx
index 427e7ff7b..6461af8ee 100644
--- a/packages/app/src/modals/ManageFastUnstake/index.tsx
+++ b/packages/app/src/modals/ManageFastUnstake/index.tsx
@@ -10,7 +10,6 @@ import { useFastUnstake } from 'contexts/FastUnstake';
import { useTransferOptions } from 'contexts/TransferOptions';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { useUnstaking } from 'hooks/useUnstaking';
import { Close } from 'library/Modal/Close';
import { SubmitTx } from 'library/SubmitTx';
@@ -23,22 +22,24 @@ import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
import { ModalNotes } from 'kits/Overlay/structure/ModalNotes';
import { planckToUnitBn } from 'library/Utils';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const ManageFastUnstake = () => {
const { t } = useTranslation('modals');
const {
- api,
consts: { bondDuration, fastUnstakeDeposit },
networkMetrics: { fastUnstakeErasToCheckPerBlock },
activeEra,
} = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
- const { activeAccount } = useActiveAccounts();
const { notEnoughFunds } = useTxMeta();
const { getBondedAccount } = useBonded();
const { isFastUnstaking } = useUnstaking();
+ const { activeAccount } = useActiveAccounts();
const { setModalResize, setModalStatus } = useOverlay().modal;
const { getSignerWarnings } = useSignerWarnings();
const { feeReserve, getTransferOptions } = useTransferOptions();
@@ -82,14 +83,15 @@ export const ManageFastUnstake = () => {
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!valid || !api) {
+ if (!valid || !pApi) {
return tx;
}
if (!isFastUnstaking) {
- tx = api.tx.fastUnstake.registerFastUnstake();
+ tx = pApi.tx.FastUnstake.register_fast_unstake();
} else {
- tx = api.tx.fastUnstake.deregister();
+ tx = pApi.tx.FastUnstake.deregister();
}
return tx;
};
diff --git a/packages/app/src/modals/ManagePool/Forms/ClaimCommission/index.tsx b/packages/app/src/modals/ManagePool/Forms/ClaimCommission/index.tsx
index 94f98eb6b..164328636 100644
--- a/packages/app/src/modals/ManagePool/Forms/ClaimCommission/index.tsx
+++ b/packages/app/src/modals/ManagePool/Forms/ClaimCommission/index.tsx
@@ -7,11 +7,9 @@ import BigNumber from 'bignumber.js';
import type { Dispatch, SetStateAction } from 'react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import { useOverlay } from 'kits/Overlay/Provider';
import { useNetwork } from 'contexts/Network';
@@ -22,6 +20,8 @@ import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
import { ModalNotes } from 'kits/Overlay/structure/ModalNotes';
import { planckToUnitBn } from 'library/Utils';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const ClaimCommission = ({
setSection,
@@ -29,8 +29,8 @@ export const ClaimCommission = ({
setSection: Dispatch>;
}) => {
const { t } = useTranslation('modals');
- const { api } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { setModalStatus } = useOverlay().modal;
@@ -52,10 +52,11 @@ export const ClaimCommission = ({
// tx to submit
const getTx = () => {
- if (!valid || !api) {
+ const { pApi } = ApiController.get(network);
+ if (!valid || !pApi || poolId === undefined) {
return null;
}
- return api.tx.nominationPools.claimCommission(poolId);
+ return pApi.tx.NominationPools.claim_commission({ pool_id: poolId });
};
const submitExtrinsic = useSubmitExtrinsic({
diff --git a/packages/app/src/modals/ManagePool/Forms/LeavePool/index.tsx b/packages/app/src/modals/ManagePool/Forms/LeavePool/index.tsx
index 468189a32..0f7c2a087 100644
--- a/packages/app/src/modals/ManagePool/Forms/LeavePool/index.tsx
+++ b/packages/app/src/modals/ManagePool/Forms/LeavePool/index.tsx
@@ -13,7 +13,6 @@ import { useTransferOptions } from 'contexts/TransferOptions';
import { Warning } from 'library/Form/Warning';
import { useErasToTimeLeft } from 'hooks/useErasToTimeLeft';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { timeleftAsString, planckToUnitBn } from 'library/Utils';
import { SubmitTx } from 'library/SubmitTx';
import { StaticNote } from 'modals/Utils/StaticNote';
@@ -24,6 +23,8 @@ import { ButtonSubmitInvert } from 'ui-buttons';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const LeavePool = ({
setSection,
@@ -31,8 +32,9 @@ export const LeavePool = ({
setSection: Dispatch>;
}) => {
const { t } = useTranslation('modals');
- const { api, consts } = useApi();
+ const { consts } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { erasToSeconds } = useErasToTimeLeft();
@@ -80,8 +82,9 @@ export const LeavePool = ({
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!api || !activeAccount) {
+ if (!pApi || !activeAccount) {
return tx;
}
@@ -90,7 +93,13 @@ export const LeavePool = ({
units
).toString();
- tx = api.tx.nominationPools.unbond(activeAccount, bondToSubmit);
+ tx = pApi.tx.NominationPools.unbond({
+ member_account: {
+ type: 'Id',
+ value: activeAccount,
+ },
+ unbonding_points: BigInt(bondToSubmit),
+ });
return tx;
};
diff --git a/packages/app/src/modals/ManagePool/Forms/ManageCommission/index.tsx b/packages/app/src/modals/ManagePool/Forms/ManageCommission/index.tsx
index 5fca29e24..97aedbec7 100644
--- a/packages/app/src/modals/ManagePool/Forms/ManageCommission/index.tsx
+++ b/packages/app/src/modals/ManagePool/Forms/ManageCommission/index.tsx
@@ -11,9 +11,7 @@ import { useHelp } from 'contexts/Help';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { useBondedPools } from 'contexts/Pools/BondedPools';
import { Warning } from 'library/Form/Warning';
-import { useBatchCall } from 'hooks/useBatchCall';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import 'rc-slider/assets/index.css';
import { useOverlay } from 'kits/Overlay/Provider';
@@ -26,6 +24,10 @@ import { ButtonHelp, ButtonSubmitInvert } from 'ui-buttons';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useBatchCall } from 'hooks/useBatchCall';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const ManageCommission = ({
setSection,
@@ -37,15 +39,8 @@ export const ManageCommission = ({
const { t } = useTranslation('modals');
const { openHelp } = useHelp();
const {
- api,
poolsConfig: { globalMaxCommission },
} = useApi();
- const { newBatchCall } = useBatchCall();
- const { activeAccount } = useActiveAccounts();
- const { setModalStatus } = useOverlay().modal;
- const { isOwner, activePool } = useActivePool();
- const { getSignerWarnings } = useSignerWarnings();
- const { getBondedPool, updateBondedPools } = useBondedPools();
const {
getInitial,
getCurrent,
@@ -55,6 +50,13 @@ export const ManageCommission = ({
resetAll,
isUpdated,
} = usePoolCommission();
+ const { network } = useNetwork();
+ const { newBatchCall } = useBatchCall();
+ const { activeAccount } = useActiveAccounts();
+ const { setModalStatus } = useOverlay().modal;
+ const { isOwner, activePool } = useActivePool();
+ const { getSignerWarnings } = useSignerWarnings();
+ const { getBondedPool, updateBondedPools } = useBondedPools();
const poolId = activePool?.id || 0;
const bondedPool = getBondedPool(poolId);
@@ -125,39 +127,45 @@ export const ManageCommission = ({
// tx to submit.
const getTx = () => {
- if (!valid || !api) {
+ const { pApi } = ApiController.get(network);
+ if (!valid || !pApi) {
return null;
}
const txs = [];
if (commissionUpdated) {
txs.push(
- api.tx.nominationPools.setCommission(
- poolId,
- currentCommissionSet
+ pApi.tx.NominationPools.set_commission({
+ pool_id: poolId,
+ new_commission: currentCommissionSet
? [
- new BigNumber(commission).multipliedBy(10000000).toString(),
+ new BigNumber(commission).multipliedBy(10000000).toNumber(),
payee,
]
- : null
- )
+ : undefined,
+ })
);
}
if (isUpdated('max_commission') && getEnabled('max_commission')) {
txs.push(
- api.tx.nominationPools.setCommissionMax(
- poolId,
- new BigNumber(maxCommission).multipliedBy(10000000).toString()
- )
+ pApi.tx.NominationPools.set_commission_max({
+ pool_id: poolId,
+ max_commission: new BigNumber(maxCommission)
+ .multipliedBy(10000000)
+ .toNumber(),
+ })
);
}
if (isUpdated('change_rate') && getEnabled('change_rate')) {
txs.push(
- api.tx.nominationPools.setCommissionChangeRate(poolId, {
- maxIncrease: new BigNumber(changeRate.maxIncrease)
- .multipliedBy(10000000)
- .toString(),
- minDelay: changeRate.minDelay.toString(),
+ pApi.tx.NominationPools.set_commission_change_rate({
+ pool_id: poolId,
+ change_rate: {
+ max_increase: new BigNumber(changeRate.maxIncrease)
+ .multipliedBy(10000000)
+ .toNumber(),
+ min_delay: changeRate.minDelay.toNumber(),
+ },
})
);
}
diff --git a/packages/app/src/modals/ManagePool/Forms/RenamePool/index.tsx b/packages/app/src/modals/ManagePool/Forms/RenamePool/index.tsx
index c9db0c8a5..ddd2f11d0 100644
--- a/packages/app/src/modals/ManagePool/Forms/RenamePool/index.tsx
+++ b/packages/app/src/modals/ManagePool/Forms/RenamePool/index.tsx
@@ -6,18 +6,20 @@ import { u8aUnwrapBytes, u8aToString } from '@polkadot/util';
import type { Dispatch, FormEvent, SetStateAction } from 'react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { useBondedPools } from 'contexts/Pools/BondedPools';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import { useOverlay } from 'kits/Overlay/Provider';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { ButtonSubmitInvert } from 'ui-buttons';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { Binary } from 'polkadot-api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const RenamePool = ({
setSection,
@@ -27,7 +29,7 @@ export const RenamePool = ({
section: number;
}) => {
const { t } = useTranslation('modals');
- const { api } = useApi();
+ const { network } = useNetwork();
const { setModalStatus } = useOverlay().modal;
const { activeAccount } = useActiveAccounts();
const { isOwner, activePool } = useActivePool();
@@ -58,10 +60,14 @@ export const RenamePool = ({
// tx to submit
const getTx = () => {
- if (!valid || !api) {
+ const { pApi } = ApiController.get(network);
+ if (!valid || !pApi) {
return null;
}
- return api.tx.nominationPools.setMetadata(poolId, metadata);
+ return pApi.tx.NominationPools.set_metadata({
+ pool_id: poolId,
+ metadata: Binary.fromText(metadata),
+ });
};
const submitExtrinsic = useSubmitExtrinsic({
diff --git a/packages/app/src/modals/ManagePool/Forms/SetClaimPermission/index.tsx b/packages/app/src/modals/ManagePool/Forms/SetClaimPermission/index.tsx
index 530119ffe..aebd963b3 100644
--- a/packages/app/src/modals/ManagePool/Forms/SetClaimPermission/index.tsx
+++ b/packages/app/src/modals/ManagePool/Forms/SetClaimPermission/index.tsx
@@ -5,12 +5,10 @@ import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';
import type { Dispatch, SetStateAction } from 'react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { ClaimPermissionInput } from 'library/Form/ClaimPermissionInput';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import { useOverlay } from 'kits/Overlay/Provider';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
@@ -20,6 +18,9 @@ import { ButtonSubmitInvert } from 'ui-buttons';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { defaultClaimPermission } from 'controllers/ActivePools/defaults';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const SetClaimPermission = ({
setSection,
@@ -29,7 +30,7 @@ export const SetClaimPermission = ({
setSection: Dispatch>;
}) => {
const { t } = useTranslation('modals');
- const { api } = useApi();
+ const { network } = useNetwork();
const { getPoolMembership } = useBalances();
const { activeAccount } = useActiveAccounts();
const { setModalStatus } = useOverlay().modal;
@@ -60,10 +61,15 @@ export const SetClaimPermission = ({
// tx to submit.
const getTx = () => {
- if (!valid || !api) {
+ const { pApi } = ApiController.get(network);
+ if (!valid || !pApi) {
return null;
}
- return api.tx.nominationPools.setClaimPermission(claimPermission);
+ return pApi.tx.NominationPools.set_claim_permission({
+ permission: {
+ type: claimPermission,
+ },
+ });
};
const submitExtrinsic = useSubmitExtrinsic({
diff --git a/packages/app/src/modals/ManagePool/Forms/SetPoolState/index.tsx b/packages/app/src/modals/ManagePool/Forms/SetPoolState/index.tsx
index 302cd21d4..5b0e83129 100644
--- a/packages/app/src/modals/ManagePool/Forms/SetPoolState/index.tsx
+++ b/packages/app/src/modals/ManagePool/Forms/SetPoolState/index.tsx
@@ -5,12 +5,10 @@ import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';
import type { Dispatch, SetStateAction } from 'react';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { useBondedPools } from 'contexts/Pools/BondedPools';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import { useOverlay } from 'kits/Overlay/Provider';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
@@ -18,6 +16,9 @@ import { ButtonSubmitInvert } from 'ui-buttons';
import { ActionItem } from 'library/ActionItem';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const SetPoolState = ({
setSection,
@@ -27,7 +28,7 @@ export const SetPoolState = ({
task?: string;
}) => {
const { t } = useTranslation('modals');
- const { api } = useApi();
+ const { network } = useNetwork();
const { setModalStatus } = useOverlay().modal;
const { activeAccount } = useActiveAccounts();
const { getSignerWarnings } = useSignerWarnings();
@@ -80,20 +81,30 @@ export const SetPoolState = ({
// tx to submit
const getTx = () => {
- if (!valid || !api) {
+ const { pApi } = ApiController.get(network);
+ if (!valid || !pApi || poolId === undefined) {
return null;
}
let tx;
switch (task) {
case 'destroy_pool':
- tx = api.tx.nominationPools.setState(poolId, 'Destroying');
+ tx = pApi.tx.NominationPools.set_state({
+ pool_id: poolId,
+ state: { type: 'Destroying' },
+ });
break;
case 'unlock_pool':
- tx = api.tx.nominationPools.setState(poolId, 'Open');
+ tx = pApi.tx.NominationPools.set_state({
+ pool_id: poolId,
+ state: { type: 'Open' },
+ });
break;
case 'lock_pool':
- tx = api.tx.nominationPools.setState(poolId, 'Blocked');
+ tx = pApi.tx.NominationPools.set_state({
+ pool_id: poolId,
+ state: { type: 'Blocked' },
+ });
break;
default:
tx = null;
diff --git a/packages/app/src/modals/StopNominations/index.tsx b/packages/app/src/modals/StopNominations/index.tsx
index 486783c9e..918404ade 100644
--- a/packages/app/src/modals/StopNominations/index.tsx
+++ b/packages/app/src/modals/StopNominations/index.tsx
@@ -3,12 +3,10 @@
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useBonded } from 'contexts/Bonded';
import { useActivePool } from 'contexts/Pools/ActivePool';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Close } from 'library/Modal/Close';
import { SubmitTx } from 'library/SubmitTx';
import { useTxMeta } from 'contexts/TxMeta';
@@ -18,10 +16,13 @@ import { useBalances } from 'contexts/Balances';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ModalSeparator } from 'kits/Overlay/structure/ModalSeparator';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const StopNominations = () => {
const { t } = useTranslation('modals');
- const { api } = useApi();
+ const { network } = useNetwork();
const { notEnoughFunds } = useTxMeta();
const { getBondedAccount } = useBonded();
const { getNominations } = useBalances();
@@ -62,16 +63,17 @@ export const StopNominations = () => {
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!valid || !api) {
+ if (!valid || !pApi) {
return tx;
}
if (isPool) {
// wishing to stop all nominations, call chill
- tx = api.tx.nominationPools.chill(activePool?.id || 0);
+ tx = pApi.tx.NominationPools.chill({ pool_id: activePool?.id || 0 });
} else if (isStaking) {
- tx = api.tx.staking.chill();
+ tx = pApi.tx.Staking.chill();
}
return tx;
};
diff --git a/packages/app/src/modals/Unbond/index.tsx b/packages/app/src/modals/Unbond/index.tsx
index 28f7c3358..0753c2665 100644
--- a/packages/app/src/modals/Unbond/index.tsx
+++ b/packages/app/src/modals/Unbond/index.tsx
@@ -15,7 +15,6 @@ import { UnbondFeedback } from 'library/Form/Unbond/UnbondFeedback';
import { Warning } from 'library/Form/Warning';
import { useErasToTimeLeft } from 'hooks/useErasToTimeLeft';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { timeleftAsString, planckToUnitBn } from 'library/Utils';
import { Close } from 'library/Modal/Close';
import { SubmitTx } from 'library/SubmitTx';
@@ -26,6 +25,8 @@ import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ModalNotes } from 'kits/Overlay/structure/ModalNotes';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const Unbond = () => {
const { t } = useTranslation('modals');
@@ -34,6 +35,7 @@ export const Unbond = () => {
const { notEnoughFunds } = useTxMeta();
const { getBondedAccount } = useBonded();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { erasToSeconds } = useErasToTimeLeft();
@@ -47,7 +49,6 @@ export const Unbond = () => {
config: { options },
} = useOverlay().modal;
const {
- api,
consts,
poolsConfig: { minJoinBond: minJoinBondBn, minCreateBond: minCreateBondBn },
} = useApi();
@@ -104,8 +105,9 @@ export const Unbond = () => {
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!api || !activeAccount) {
+ if (!pApi || !activeAccount) {
return tx;
}
@@ -116,9 +118,12 @@ export const Unbond = () => {
// determine tx
if (isPooling) {
- tx = api.tx.nominationPools.unbond(activeAccount, bondToSubmit);
+ tx = pApi.tx.NominationPools.unbond({
+ member_account: { type: 'Id', value: activeAccount },
+ unbonding_points: BigInt(bondToSubmit),
+ });
} else if (isStaking) {
- tx = api.tx.staking.unbond(bondToSubmit);
+ tx = pApi.tx.Staking.unbond({ value: BigInt(bondToSubmit) });
}
return tx;
};
diff --git a/packages/app/src/modals/UnlockChunks/Forms.tsx b/packages/app/src/modals/UnlockChunks/Forms.tsx
index 2d5c216d1..869617ef6 100644
--- a/packages/app/src/modals/UnlockChunks/Forms.tsx
+++ b/packages/app/src/modals/UnlockChunks/Forms.tsx
@@ -15,7 +15,6 @@ import { usePoolMembers } from 'contexts/Pools/PoolMembers';
import { useFavoritePools } from 'contexts/Pools/FavoritePools';
import { Warning } from 'library/Form/Warning';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { SubmitTx } from 'library/SubmitTx';
import { useOverlay } from 'kits/Overlay/Provider';
import { useNetwork } from 'contexts/Network';
@@ -28,6 +27,8 @@ import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
import { planckToUnitBn } from 'library/Utils';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const Forms = forwardRef(
(
@@ -35,8 +36,9 @@ export const Forms = forwardRef(
ref: ForwardedRef
) => {
const { t } = useTranslation('modals');
- const { api, consts } = useApi();
+ const { consts } = useApi();
const {
+ network,
networkData: { units, unit },
} = useNetwork();
const { activePool } = useActivePool();
@@ -67,20 +69,28 @@ export const Forms = forwardRef(
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
- if (!valid || !api || !unlock) {
+ if (!valid || !pApi || !unlock) {
return tx;
}
// rebond is only available when staking directly.
if (task === 'rebond' && isStaking) {
- tx = api.tx.staking.rebond(unlock.value.toNumber() || 0);
+ tx = pApi.tx.Staking.rebond({
+ value: BigInt(unlock.value.toNumber() || 0),
+ });
} else if (task === 'withdraw' && isStaking) {
- tx = api.tx.staking.withdrawUnbonded(historyDepth.toString());
+ tx = pApi.tx.Staking.withdraw_unbonded({
+ num_slashing_spans: historyDepth.toNumber(),
+ });
} else if (task === 'withdraw' && isPooling && activePool) {
- tx = api.tx.nominationPools.withdrawUnbonded(
- activeAccount,
- historyDepth.toString()
- );
+ tx = pApi.tx.NominationPools.withdraw_unbonded({
+ member_account: {
+ type: 'Id',
+ value: activeAccount,
+ },
+ num_slashing_spans: historyDepth.toNumber(),
+ });
}
return tx;
};
diff --git a/packages/app/src/modals/Unstake/index.tsx b/packages/app/src/modals/Unstake/index.tsx
index 4e113fbb2..52d99b812 100644
--- a/packages/app/src/modals/Unstake/index.tsx
+++ b/packages/app/src/modals/Unstake/index.tsx
@@ -9,10 +9,8 @@ import { useApi } from 'contexts/Api';
import { useBonded } from 'contexts/Bonded';
import { useTransferOptions } from 'contexts/TransferOptions';
import { Warning } from 'library/Form/Warning';
-import { useBatchCall } from 'hooks/useBatchCall';
import { useErasToTimeLeft } from 'hooks/useErasToTimeLeft';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { timeleftAsString, planckToUnitBn } from 'library/Utils';
import { Close } from 'library/Modal/Close';
import { SubmitTx } from 'library/SubmitTx';
@@ -25,13 +23,17 @@ import { useBalances } from 'contexts/Balances';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
import { ActionItem } from 'library/ActionItem';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
+import { ApiController } from 'controllers/Api';
+import { useBatchCall } from 'hooks/useBatchCall';
export const Unstake = () => {
const { t } = useTranslation('modals');
const {
+ network,
networkData: { units, unit },
} = useNetwork();
- const { api, consts } = useApi();
+ const { consts } = useApi();
const { notEnoughFunds } = useTxMeta();
const { newBatchCall } = useBatchCall();
const { getBondedAccount } = useBonded();
@@ -80,8 +82,9 @@ export const Unstake = () => {
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
const tx = null;
- if (!api || !activeAccount) {
+ if (!pApi || !activeAccount) {
return tx;
}
// remove decimal errors
@@ -91,11 +94,11 @@ export const Unstake = () => {
);
if (bondToSubmit == 0n) {
- return api.tx.staking.chill();
+ return pApi.tx.Staking.chill();
}
const txs = [
- api.tx.staking.chill(),
- api.tx.staking.unbond(bondToSubmit.toString()),
+ pApi.tx.Staking.chill(),
+ pApi.tx.Staking.unbond({ value: BigInt(bondToSubmit.toString()) }),
];
return newBatchCall(txs, controller);
};
diff --git a/packages/app/src/modals/UpdatePayee/index.tsx b/packages/app/src/modals/UpdatePayee/index.tsx
index f090e30e5..2d70855e6 100644
--- a/packages/app/src/modals/UpdatePayee/index.tsx
+++ b/packages/app/src/modals/UpdatePayee/index.tsx
@@ -4,13 +4,11 @@
import { isValidAddress } from '@w3ux/utils';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useBonded } from 'contexts/Bonded';
import type { PayeeConfig, PayeeOptions } from 'contexts/Setup/types';
import { Warning } from 'library/Form/Warning';
import { usePayeeConfig } from 'hooks/usePayeeConfig';
import { useSignerWarnings } from 'hooks/useSignerWarnings';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Title } from 'library/Modal/Title';
import { PayeeInput } from 'library/PayeeInput';
import { SelectItems } from 'library/SelectItems';
@@ -23,10 +21,13 @@ import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { useBalances } from 'contexts/Balances';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
import { ModalWarnings } from 'kits/Overlay/structure/ModalWarnings';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const UpdatePayee = () => {
const { t } = useTranslation('modals');
- const { api } = useApi();
+ const { network } = useNetwork();
const { getPayee } = useBalances();
const { notEnoughFunds } = useTxMeta();
const { getBondedAccount } = useBonded();
@@ -72,20 +73,21 @@ export const UpdatePayee = () => {
// Tx to submit.
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
-
- if (!api) {
+ if (!pApi) {
return tx;
}
const payeeToSubmit = !isComplete()
- ? 'Staked'
+ ? { type: 'Staked' }
: selected.destination === 'Account'
? {
- Account: selected.account,
+ type: 'Account',
+ value: selected.account,
}
- : selected.destination;
+ : { type: selected.destination };
- tx = api.tx.staking.setPayee(payeeToSubmit);
+ tx = pApi.tx.Staking.set_payee({ payee: payeeToSubmit });
return tx;
};
From bbdec4b396cf623865959aa5d0c5e4b012ad4584 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 11:46:35 +0700
Subject: [PATCH 59/84] migrate remaining tx, stop exposing pjs api
---
.../src/canvas/CreatePool/Summary/index.tsx | 2 +-
packages/app/src/contexts/Api/defaults.ts | 1 -
packages/app/src/contexts/Api/index.tsx | 1 -
packages/app/src/contexts/Api/types.ts | 1 -
.../src/contexts/Pools/ActivePool/index.tsx | 4 +--
.../src/contexts/Pools/JoinPools/index.tsx | 4 +--
.../contexts/Pools/PoolPerformance/index.tsx | 5 ++-
packages/app/src/contexts/Staking/index.tsx | 10 +++---
.../app/src/modals/ChangePoolRoles/index.tsx | 34 +++++++++++++------
.../src/modals/ImportWalletConnect/index.tsx | 4 +--
10 files changed, 37 insertions(+), 29 deletions(-)
diff --git a/packages/app/src/canvas/CreatePool/Summary/index.tsx b/packages/app/src/canvas/CreatePool/Summary/index.tsx
index 149cd7058..5af046668 100644
--- a/packages/app/src/canvas/CreatePool/Summary/index.tsx
+++ b/packages/app/src/canvas/CreatePool/Summary/index.tsx
@@ -81,7 +81,7 @@ export const Summary = ({ section }: SetupStepProps) => {
}),
pApi.tx.NominationPools.set_metadata({
pool_id: poolId.toNumber(),
- metadata: Binary.fromHex(metadata),
+ metadata: Binary.fromText(metadata),
}),
];
return newBatchCall(txs, activeAccount);
diff --git a/packages/app/src/contexts/Api/defaults.ts b/packages/app/src/contexts/Api/defaults.ts
index 6c03b014a..c1ea6362a 100644
--- a/packages/app/src/contexts/Api/defaults.ts
+++ b/packages/app/src/contexts/Api/defaults.ts
@@ -80,7 +80,6 @@ export const defaultStakingMetrics: APIStakingMetrics = {
};
export const defaultApiContext: APIContextInterface = {
- api: null,
peopleApi: null,
chainSpecs: defaultChainSpecs,
isReady: false,
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 279eac3cd..65d516410 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -549,7 +549,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
return (
useContext(ActivePoolContext);
export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
const { getPoolMembership } = useBalances();
- const { isReady, api, peopleApi } = useApi();
+ const { isReady, peopleApi } = useApi();
const { activeAccount } = useActiveAccounts();
const createPoolAccounts = useCreatePoolAccounts();
@@ -71,7 +71,7 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
// Sync active pool subscriptions.
const syncActivePoolSubscriptions = async () => {
- if (api && accountPoolId) {
+ if (isReady && accountPoolId) {
const newActivePool = [
{
id: accountPoolId,
diff --git a/packages/app/src/contexts/Pools/JoinPools/index.tsx b/packages/app/src/contexts/Pools/JoinPools/index.tsx
index 150f4eca7..df7cfb742 100644
--- a/packages/app/src/contexts/Pools/JoinPools/index.tsx
+++ b/packages/app/src/contexts/Pools/JoinPools/index.tsx
@@ -22,7 +22,7 @@ export const useJoinPools = () => useContext(JoinPoolsContext);
export const JoinPoolsProvider = ({ children }: { children: ReactNode }) => {
const {
- api,
+ isReady,
activeEra,
networkMetrics: { minimumActiveStake },
} = useApi();
@@ -45,7 +45,7 @@ export const JoinPoolsProvider = ({ children }: { children: ReactNode }) => {
// Trigger worker to calculate join pool performance data.
useEffectIgnoreInitial(() => {
if (
- api &&
+ isReady &&
bondedPools.length &&
activeEra.index.isGreaterThan(0) &&
erasRewardPointsFetched === 'synced' &&
diff --git a/packages/app/src/contexts/Pools/PoolPerformance/index.tsx b/packages/app/src/contexts/Pools/PoolPerformance/index.tsx
index 3413570c7..1a09e1740 100644
--- a/packages/app/src/contexts/Pools/PoolPerformance/index.tsx
+++ b/packages/app/src/contexts/Pools/PoolPerformance/index.tsx
@@ -38,7 +38,7 @@ export const PoolPerformanceProvider = ({
children: ReactNode;
}) => {
const { network } = useNetwork();
- const { api, activeEra } = useApi();
+ const { isReady, activeEra } = useApi();
const { getPagedErasStakers } = useStaking();
const { erasRewardPoints } = useValidators();
@@ -179,10 +179,9 @@ export const PoolPerformanceProvider = ({
// Get era data and send to worker.
const processEra = async (key: PoolRewardPointsKey, era: BigNumber) => {
- if (!api) {
+ if (!isReady) {
return;
}
-
// NOTE: This will not make any difference on the first run.
updateTaskCurrentEra(key, era);
diff --git a/packages/app/src/contexts/Staking/index.tsx b/packages/app/src/contexts/Staking/index.tsx
index 1a84bd4c7..ea0cd3c49 100644
--- a/packages/app/src/contexts/Staking/index.tsx
+++ b/packages/app/src/contexts/Staking/index.tsx
@@ -41,7 +41,7 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
const { getBondedAccount } = useBonded();
const { networkData, network } = useNetwork();
const { getLedger, getNominations } = useBalances();
- const { isReady, api, activeEra, apiStatus } = useApi();
+ const { isReady, activeEra, apiStatus } = useApi();
const { accounts: connectAccounts } = useImportedAccounts();
const { activeAccount, getActiveAccount } = useActiveAccounts();
@@ -93,7 +93,7 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
// Fetches erasStakers exposures for an era, and saves to `localStorage`.
const fetchEraStakers = async (era: string) => {
- if (!isReady || activeEra.index.isZero() || !api) {
+ if (!isReady || activeEra.index.isZero()) {
return [];
}
@@ -120,7 +120,7 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
// Fetches the active nominator set and metadata around it.
const fetchActiveEraStakers = async () => {
- if (!isReady || activeEra.index.isZero() || !api) {
+ if (!isReady || activeEra.index.isZero()) {
return;
}
@@ -224,11 +224,11 @@ export const StakingProvider = ({ children }: { children: ReactNode }) => {
// Fetch eras stakers from storage.
const getPagedErasStakers = async (era: string) => {
- if (!api) {
+ const { pApi } = ApiController.get(network);
+ if (!pApi) {
return [];
}
- const { pApi } = ApiController.get(network);
const overview = await new ErasStakersOverview(pApi).fetch(era);
const validators: Record = overview.reduce(
(
diff --git a/packages/app/src/modals/ChangePoolRoles/index.tsx b/packages/app/src/modals/ChangePoolRoles/index.tsx
index 8c652afe6..5fcb9aef7 100644
--- a/packages/app/src/modals/ChangePoolRoles/index.tsx
+++ b/packages/app/src/modals/ChangePoolRoles/index.tsx
@@ -2,9 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-only
import { useTranslation } from 'react-i18next';
-import { useApi } from 'contexts/Api';
import { useBondedPools } from 'contexts/Pools/BondedPools';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Close } from 'library/Modal/Close';
import { SubmitTx } from 'library/SubmitTx';
import { useTxMeta } from 'contexts/TxMeta';
@@ -14,13 +12,16 @@ import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { RoleChange } from './RoleChange';
import { Wrapper } from './Wrapper';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
+import { ApiController } from 'controllers/Api';
+import { useNetwork } from 'contexts/Network';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
export const ChangePoolRoles = () => {
const { t } = useTranslation('modals');
- const { api } = useApi();
- const { activeAccount } = useActiveAccounts();
+ const { network } = useNetwork();
const { notEnoughFunds } = useTxMeta();
const { replacePoolRoles } = useBondedPools();
+ const { activeAccount } = useActiveAccounts();
const {
setModalStatus,
config: { options },
@@ -30,18 +31,29 @@ export const ChangePoolRoles = () => {
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
let tx = null;
+ if (!pApi) {
+ return tx;
+ }
+
+ const removeOp = { type: 'Remove' };
const root = roleEdits?.root?.newAddress
- ? { Set: roleEdits?.root?.newAddress }
- : 'Remove';
+ ? { type: 'Set', value: roleEdits.root.newAddress }
+ : removeOp;
const nominator = roleEdits?.nominator?.newAddress
- ? { Set: roleEdits?.nominator?.newAddress }
- : 'Remove';
+ ? { type: 'Set', value: roleEdits.nominator.newAddress }
+ : removeOp;
const bouncer = roleEdits?.bouncer?.newAddress
- ? { Set: roleEdits?.bouncer?.newAddress }
- : 'Remove';
+ ? { type: 'Set', value: roleEdits.bouncer.newAddress }
+ : removeOp;
- tx = api?.tx.nominationPools?.updateRoles(poolId, root, nominator, bouncer);
+ tx = pApi.tx.NominationPools.update_roles({
+ pool_id: poolId,
+ new_root: root,
+ new_nominator: nominator,
+ new_bouncer: bouncer,
+ });
return tx;
};
diff --git a/packages/app/src/modals/ImportWalletConnect/index.tsx b/packages/app/src/modals/ImportWalletConnect/index.tsx
index b1b2dff3d..05f513681 100644
--- a/packages/app/src/modals/ImportWalletConnect/index.tsx
+++ b/packages/app/src/modals/ImportWalletConnect/index.tsx
@@ -25,7 +25,7 @@ export const ImportWalletConnect = () => {
const { t } = useTranslation();
const { addWcAccount, getWcAccounts, wcAccountExists, renameWcAccount } =
useWcAccounts();
- const { api } = useApi();
+ const { isReady } = useApi();
const { network } = useNetwork();
const { status: promptStatus } = usePrompt();
const { replaceModal, setModalResize } = useOverlay().modal;
@@ -41,7 +41,7 @@ export const ImportWalletConnect = () => {
// Handle wallet account importing.
const handleImportAddresses = async () => {
- if (!wcInitialized || !api) {
+ if (!wcInitialized || !isReady) {
return;
}
From 88d011952fc768cc4e650f629e0af765c50deeba Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 11:48:11 +0700
Subject: [PATCH 60/84] fixes
---
.../app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx | 4 ++--
packages/app/src/contexts/Balances/index.tsx | 4 ++--
packages/app/src/contexts/Connect/ImportedAccounts/index.tsx | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx b/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx
index 715a280c8..98d829481 100644
--- a/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx
+++ b/packages/app/src/canvas/PoolMembers/Prompts/WithdrawMember.tsx
@@ -39,7 +39,7 @@ export const WithdrawMember = ({
networkData: { units, unit },
} = useNetwork();
const { closePrompt } = usePrompt();
- const { api, consts, activeEra } = useApi();
+ const { consts, activeEra } = useApi();
const { activeAccount } = useActiveAccounts();
const { removePoolMember } = usePoolMembers();
const { getSignerWarnings } = useSignerWarnings();
@@ -69,7 +69,7 @@ export const WithdrawMember = ({
const getTx = () => {
const { pApi } = ApiController.get(network);
let tx = null;
- if (!valid || !api) {
+ if (!valid || !pApi) {
return tx;
}
tx = pApi.tx.NominationPools.withdraw_unbonded({
diff --git a/packages/app/src/contexts/Balances/index.tsx b/packages/app/src/contexts/Balances/index.tsx
index 7564d4fea..92abd42a4 100644
--- a/packages/app/src/contexts/Balances/index.tsx
+++ b/packages/app/src/contexts/Balances/index.tsx
@@ -27,7 +27,7 @@ export const useBalances = () => useContext(BalancesContext);
export const BalancesProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
- const { api, peopleApi } = useApi();
+ const { peopleApi, isReady } = useApi();
const { getBondedAccount } = useBonded();
const { accounts } = useImportedAccounts();
const createPoolAccounts = useCreatePoolAccounts();
@@ -61,7 +61,7 @@ export const BalancesProvider = ({ children }: { children: ReactNode }) => {
// If a pool membership exists, let `ActivePools` know of pool membership to re-sync pool
// details and nominations.
- if (api && poolMembership) {
+ if (isReady && poolMembership) {
const { poolId } = poolMembership;
const newPools = ActivePoolsController.getformattedPoolItems(
address
diff --git a/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx b/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx
index bac80eb17..7f7de3c98 100644
--- a/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx
+++ b/packages/app/src/contexts/Connect/ImportedAccounts/index.tsx
@@ -32,7 +32,7 @@ export const ImportedAccountsProvider = ({
}: {
children: ReactNode;
}) => {
- const { isReady, api } = useApi();
+ const { isReady } = useApi();
const {
network,
networkData: { ss58 },
@@ -115,7 +115,7 @@ export const ImportedAccountsProvider = ({
// Keep accounts in sync with `BalancesController`.
useEffectIgnoreInitial(() => {
- if (api && isReady) {
+ if (isReady) {
BalancesController.syncAccounts(
network,
allAccounts.map((a) => a.address)
From 50d9f08363755834f0d6944b649b3aed1ea26010 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 12:03:08 +0700
Subject: [PATCH 61/84] stop exposing `peopleApi`, combine ready events
---
packages/app/src/contexts/Api/defaults.ts | 1 -
packages/app/src/contexts/Api/index.tsx | 3 +-
packages/app/src/contexts/Api/types.ts | 2 --
packages/app/src/contexts/Balances/index.tsx | 9 +++--
.../src/contexts/Pools/ActivePool/index.tsx | 7 +++-
.../Validators/ValidatorEntries/index.tsx | 5 ++-
packages/app/src/model/Api/index.ts | 33 +++----------------
7 files changed, 21 insertions(+), 39 deletions(-)
diff --git a/packages/app/src/contexts/Api/defaults.ts b/packages/app/src/contexts/Api/defaults.ts
index c1ea6362a..a48c6668e 100644
--- a/packages/app/src/contexts/Api/defaults.ts
+++ b/packages/app/src/contexts/Api/defaults.ts
@@ -80,7 +80,6 @@ export const defaultStakingMetrics: APIStakingMetrics = {
};
export const defaultApiContext: APIContextInterface = {
- peopleApi: null,
chainSpecs: defaultChainSpecs,
isReady: false,
apiStatus: 'disconnected',
diff --git a/packages/app/src/contexts/Api/index.tsx b/packages/app/src/contexts/Api/index.tsx
index 65d516410..552cb44c1 100644
--- a/packages/app/src/contexts/Api/index.tsx
+++ b/packages/app/src/contexts/Api/index.tsx
@@ -291,7 +291,7 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
}
};
- // Handle `polkadot-api` events.
+ // Handle api status events.
const handleNewApiStatus = (e: Event) => {
if (isCustomEvent(e)) {
const { chainType } = e.detail;
@@ -549,7 +549,6 @@ export const APIProvider = ({ children, network }: APIProviderProps) => {
return (
(
defaults.defaultBalancesContext
@@ -26,8 +27,8 @@ export const BalancesContext = createContext(
export const useBalances = () => useContext(BalancesContext);
export const BalancesProvider = ({ children }: { children: ReactNode }) => {
+ const { isReady } = useApi();
const { network } = useNetwork();
- const { peopleApi, isReady } = useApi();
const { getBondedAccount } = useBonded();
const { accounts } = useImportedAccounts();
const createPoolAccounts = useCreatePoolAccounts();
@@ -69,6 +70,10 @@ export const BalancesProvider = ({ children }: { children: ReactNode }) => {
id: String(poolId),
addresses: { ...createPoolAccounts(Number(poolId)) },
});
+
+ const { pApi: peopleApi } = ApiController.get(
+ `people-${network}` as SystemChainId
+ );
if (peopleApi) {
ActivePoolsController.syncPools(network, address, newPools);
}
diff --git a/packages/app/src/contexts/Pools/ActivePool/index.tsx b/packages/app/src/contexts/Pools/ActivePool/index.tsx
index 913326aab..f5209bba7 100644
--- a/packages/app/src/contexts/Pools/ActivePool/index.tsx
+++ b/packages/app/src/contexts/Pools/ActivePool/index.tsx
@@ -17,6 +17,7 @@ import { SyncController } from 'controllers/Sync';
import { useActivePools } from 'hooks/useActivePools';
import BigNumber from 'bignumber.js';
import { ApiController } from 'controllers/Api';
+import type { SystemChainId } from 'types';
export const ActivePoolContext = createContext(
defaultActivePoolContext
@@ -25,9 +26,9 @@ export const ActivePoolContext = createContext(
export const useActivePool = () => useContext(ActivePoolContext);
export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
+ const { isReady } = useApi();
const { network } = useNetwork();
const { getPoolMembership } = useBalances();
- const { isReady, peopleApi } = useApi();
const { activeAccount } = useActiveAccounts();
const createPoolAccounts = useCreatePoolAccounts();
@@ -80,6 +81,10 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
];
SyncController.dispatch('active-pools', 'syncing');
+ const { pApi: peopleApi } = ApiController.get(
+ `people-${network}` as SystemChainId
+ );
+
if (peopleApi) {
ActivePoolsController.syncPools(network, activeAccount, newActivePool);
}
diff --git a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
index e3aea5fdd..e4fd84fde 100644
--- a/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
+++ b/packages/app/src/contexts/Validators/ValidatorEntries/index.tsx
@@ -52,7 +52,6 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
const {
isReady,
- peopleApi,
peopleApiStatus,
consts: { historyDepth },
networkMetrics: { earliestStoredSession },
@@ -324,13 +323,13 @@ export const ValidatorsProvider = ({ children }: { children: ReactNode }) => {
setAvgCommission(avg);
// NOTE: validators are shuffled before committed to state.
setValidators(shuffle(validatorEntries));
- const { pApi: peoplePapiApi } = ApiController.get(
+ const { pApi: peopleApi } = ApiController.get(
`people-${network}` as SystemChainId
);
if (peopleApi && peopleApiStatus === 'ready') {
const addresses = validatorEntries.map(({ address }) => address);
const { identities, supers } = await IdentitiesController.fetch(
- peoplePapiApi,
+ peopleApi,
addresses
);
setValidatorIdentities(identities);
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index d65f6088f..b6f75f77a 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -104,11 +104,6 @@ export class Api {
// Initialise Polkadot JS API.
this.#api = new ApiPromise({ provider: this.#provider });
- // NOTE: Unlike Polkadot JS API, Papi client does not have an asynchronous initialization
- // stage that leads to `isReady`. If using papi client, we can immediately attempt to fetch
- // the chainSpec via the client.∑
- this.initApiEvents();
-
// Wait for api to be ready.
await this.#api.isReady;
@@ -203,8 +198,8 @@ export class Api {
transactionVersion,
};
- // Dispatch 'papi-ready' event to let contexts populate constants.
- this.dispatchPapiReadyEvent();
+ // Dispatch ready eventd to let contexts populate constants.
+ this.dispatchReadyEvent();
} catch (e) {
// TODO: Expand this when PJS API has been removed. Flag an error if there are any issues
// bootstrapping chain spec. NOTE: This can happen when PAPI is the standalone connection
@@ -234,35 +229,17 @@ export class Api {
}
};
- // Handler for dispatching `papi-ready` events.
- dispatchPapiReadyEvent() {
+ // Handler for dispatching ready events.
+ dispatchReadyEvent() {
const detail: PapiReadyEvent = {
network: this.network,
chainType: this.#chainType,
...this.#papiChainSpec,
};
+ this.dispatchEvent(this.ensureEventStatus('ready'));
document.dispatchEvent(new CustomEvent('papi-ready', { detail }));
}
- // Set up API event listeners. Sends information to the UI.
- async initApiEvents() {
- this.#api.on('ready', async () => {
- this.dispatchEvent(this.ensureEventStatus('ready'));
- });
-
- this.#api.on('connected', () => {
- this.dispatchEvent(this.ensureEventStatus('connected'));
- });
-
- this.#api.on('disconnected', () => {
- this.dispatchEvent(this.ensureEventStatus('disconnected'));
- });
-
- this.#api.on('error', () => {
- this.dispatchEvent(this.ensureEventStatus('error'));
- });
- }
-
// Handler for dispatching `api-status` events.
dispatchEvent(
status: EventApiStatus,
From c1f2f5890f655a2435b0126337eb69516c5d933e Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 12:07:48 +0700
Subject: [PATCH 62/84] stop connecting to pjs
---
.../app/src/controllers/ActivePools/types.ts | 3 --
packages/app/src/model/Api/index.ts | 46 +------------------
2 files changed, 2 insertions(+), 47 deletions(-)
diff --git a/packages/app/src/controllers/ActivePools/types.ts b/packages/app/src/controllers/ActivePools/types.ts
index b838646fa..2753a60ad 100644
--- a/packages/app/src/controllers/ActivePools/types.ts
+++ b/packages/app/src/controllers/ActivePools/types.ts
@@ -1,7 +1,6 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import type { VoidFn } from '@polkadot/api/types';
import type { Nominations } from 'contexts/Balances/types';
import type { ActivePool } from 'contexts/Pools/ActivePool/types';
@@ -22,5 +21,3 @@ export interface ActivePoolItem {
export type AccountActivePools = Record;
export type AccountPoolNominations = Record;
-
-export type AccountUnsubs = Record;
diff --git a/packages/app/src/model/Api/index.ts b/packages/app/src/model/Api/index.ts
index b6f75f77a..d4a69fe68 100644
--- a/packages/app/src/model/Api/index.ts
+++ b/packages/app/src/model/Api/index.ts
@@ -1,8 +1,7 @@
// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
// SPDX-License-Identifier: GPL-3.0-only
-import { ApiPromise, WsProvider } from '@polkadot/api';
-import type { AnyApi, NetworkName, SystemChainId } from 'types';
+import type { NetworkName, SystemChainId } from 'types';
import { NetworkList, SystemChainList } from 'config/networks';
import type {
ApiChainType,
@@ -14,9 +13,6 @@ import type {
PapiReadyEvent,
} from './types';
import { SubscriptionsController } from 'controllers/Subscriptions';
-import { ScProvider } from '@polkadot/rpc-provider/substrate-connect';
-import { WellKnownChain } from '@substrate/connect';
-import * as Sc from '@substrate/connect';
import type { PolkadotClient } from 'polkadot-api';
import { createClient } from 'polkadot-api';
import { getWsProvider } from 'polkadot-api/ws-provider/web';
@@ -32,9 +28,6 @@ export class Api {
// The type of chain being connected to.
#chainType: ApiChainType;
- // API provider.
- #provider: WsProvider | ScProvider;
-
// PAPI Instance.
#papiClient: PolkadotClient;
@@ -44,19 +37,12 @@ export class Api {
// PAPI Chain Spec.
#papiChainSpec: PapiChainSpec;
- // API instance.
- #api: ApiPromise;
-
// The current RPC endpoint.
#rpcEndpoint: string;
// The current connection type.
#connectionType: ConnectionType;
- get api() {
- return this.#api;
- }
-
get papiClient() {
return this.#papiClient;
}
@@ -101,12 +87,6 @@ export class Api {
// Tell UI api is connecting.
this.dispatchEvent(this.ensureEventStatus('connecting'));
- // Initialise Polkadot JS API.
- this.#api = new ApiPromise({ provider: this.#provider });
-
- // Wait for api to be ready.
- await this.#api.isReady;
-
// Initialise PAPI API.
this.#pApi = this.#papiClient.getUnsafeApi();
@@ -128,27 +108,12 @@ export class Api {
this.#rpcEndpoint
];
- // Initialize Polkadot JS Provider.
- this.#provider = new WsProvider(endpoint);
-
- // Initialize PAPI Client.
+ // Initialize Polkadot API Client.
this.#papiClient = createClient(getWsProvider(endpoint));
}
// Dynamically load and connect to Substrate Connect.
async initScProvider() {
- // Get light client key from network list.
- const lightClientKey =
- this.#chainType === 'relay'
- ? NetworkList[this.network].endpoints.lightClientKey
- : SystemChainList[this.network].endpoints.lightClientKey;
-
- // Instantiate light client provider.
- this.#provider = new ScProvider(
- Sc as AnyApi,
- WellKnownChain[lightClientKey as keyof typeof WellKnownChain]
- );
-
// Initialise PAPI light client.
const smoldot = startFromWorker(new SmWorker());
const smMetadata = getLightClientMetadata(this.#chainType, this.network);
@@ -162,9 +127,6 @@ export class Api {
})
);
this.#papiClient = createClient(chain);
-
- // Connect to Polkadot JS API provider.
- await this.#provider.connect();
}
async fetchChainSpec() {
@@ -291,10 +253,6 @@ export class Api {
async disconnect(destroy = false) {
this.unsubscribe();
- // Disconnect provider and api.
- await this.#provider?.disconnect();
- await this.#api?.disconnect();
-
// Disconnect from PAPI Client.
this.#papiClient?.destroy();
From 7968cd864feca7c2c57d1ff2b947be9a7dc2f916 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 12:09:34 +0700
Subject: [PATCH 63/84] uninstall pjs
---
packages/app/package.json | 2 -
yarn.lock | 214 ++------------------------------------
2 files changed, 8 insertions(+), 208 deletions(-)
diff --git a/packages/app/package.json b/packages/app/package.json
index 2e68e823b..32303b36c 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -26,8 +26,6 @@
"@polkadot-api/merkleize-metadata": "^1.1.4",
"@polkadot-api/signers-common": "^0.1.1",
"@polkadot-api/substrate-bindings": "^0.9.3",
- "@polkadot/api": "^14.3.1",
- "@polkadot/rpc-provider": "^14.3.1",
"@polkawatch/ddp-client": "^2.0.20",
"@substrate/connect": "^2.0.1",
"@w3ux/extension-assets": "^1.0.0-beta.1",
diff --git a/yarn.lock b/yarn.lock
index 237b8fc47..05b7687aa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2114,21 +2114,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api-augment@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/api-augment@npm:14.3.1"
- dependencies:
- "@polkadot/api-base": "npm:14.3.1"
- "@polkadot/rpc-augment": "npm:14.3.1"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/types-augment": "npm:14.3.1"
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- tslib: "npm:^2.8.0"
- checksum: 10c0/2cb756c6b2d2e9249ef8706725ee83644e2bde323a916ade1976a653521c2680bcffef25455aeb58627ac48492b99abb89a0aeac75cfa26837fda5dde4011548
- languageName: node
- linkType: hard
-
"@polkadot/api-base@npm:12.4.2":
version: 12.4.2
resolution: "@polkadot/api-base@npm:12.4.2"
@@ -2142,19 +2127,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api-base@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/api-base@npm:14.3.1"
- dependencies:
- "@polkadot/rpc-core": "npm:14.3.1"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- rxjs: "npm:^7.8.1"
- tslib: "npm:^2.8.0"
- checksum: 10c0/8e04af99ce4594fbbf934706ff3b77a54da9c13feaa5563c50de4add2c3f6763164a558fa123af26a9d208ca5689eeedec2574b5cd12a9d83cf958f21571212f
- languageName: node
- linkType: hard
-
"@polkadot/api-derive@npm:12.4.2":
version: 12.4.2
resolution: "@polkadot/api-derive@npm:12.4.2"
@@ -2173,24 +2145,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api-derive@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/api-derive@npm:14.3.1"
- dependencies:
- "@polkadot/api": "npm:14.3.1"
- "@polkadot/api-augment": "npm:14.3.1"
- "@polkadot/api-base": "npm:14.3.1"
- "@polkadot/rpc-core": "npm:14.3.1"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- "@polkadot/util-crypto": "npm:^13.2.3"
- rxjs: "npm:^7.8.1"
- tslib: "npm:^2.8.0"
- checksum: 10c0/7939b7580dfe4469b72f1d2b006ab6a3158ab65c779b4e42e94e3d7b449b04bad0f995b18bc4dbb28f2d03e64762a93ad6391faa3c2809ae0993d0973bdd9dc3
- languageName: node
- linkType: hard
-
"@polkadot/api@npm:12.4.2, @polkadot/api@npm:^12.0.2":
version: 12.4.2
resolution: "@polkadot/api@npm:12.4.2"
@@ -2216,31 +2170,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/api@npm:14.3.1, @polkadot/api@npm:^14.3.1":
- version: 14.3.1
- resolution: "@polkadot/api@npm:14.3.1"
- dependencies:
- "@polkadot/api-augment": "npm:14.3.1"
- "@polkadot/api-base": "npm:14.3.1"
- "@polkadot/api-derive": "npm:14.3.1"
- "@polkadot/keyring": "npm:^13.2.3"
- "@polkadot/rpc-augment": "npm:14.3.1"
- "@polkadot/rpc-core": "npm:14.3.1"
- "@polkadot/rpc-provider": "npm:14.3.1"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/types-augment": "npm:14.3.1"
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/types-create": "npm:14.3.1"
- "@polkadot/types-known": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- "@polkadot/util-crypto": "npm:^13.2.3"
- eventemitter3: "npm:^5.0.1"
- rxjs: "npm:^7.8.1"
- tslib: "npm:^2.8.0"
- checksum: 10c0/5c893cef918e9914c833c03b5f9fea86673cd2e50f8bdccb913177119c83124b036d69cdc8f52fd8d999b43f2da26a5260a8812cc516cba21b3fa727bd5e8023
- languageName: node
- linkType: hard
-
"@polkadot/extension-inject@npm:0.48.2":
version: 0.48.2
resolution: "@polkadot/extension-inject@npm:0.48.2"
@@ -2273,7 +2202,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/keyring@npm:^13.0.2, @polkadot/keyring@npm:^13.2.3":
+"@polkadot/keyring@npm:^13.0.2":
version: 13.2.3
resolution: "@polkadot/keyring@npm:13.2.3"
dependencies:
@@ -2298,7 +2227,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/networks@npm:13.2.3, @polkadot/networks@npm:^13.0.2, @polkadot/networks@npm:^13.2.3":
+"@polkadot/networks@npm:13.2.3, @polkadot/networks@npm:^13.0.2":
version: 13.2.3
resolution: "@polkadot/networks@npm:13.2.3"
dependencies:
@@ -2322,19 +2251,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/rpc-augment@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/rpc-augment@npm:14.3.1"
- dependencies:
- "@polkadot/rpc-core": "npm:14.3.1"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- tslib: "npm:^2.8.0"
- checksum: 10c0/9a55690656c3e8154745439e1bc7f0e9d29af19d20374724bc9f21400540efe6f5d94bb18faf5336061e16f86afdeecf0d5f3e7b0ccfad5b87f602c5633d4743
- languageName: node
- linkType: hard
-
"@polkadot/rpc-core@npm:12.4.2":
version: 12.4.2
resolution: "@polkadot/rpc-core@npm:12.4.2"
@@ -2349,20 +2265,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/rpc-core@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/rpc-core@npm:14.3.1"
- dependencies:
- "@polkadot/rpc-augment": "npm:14.3.1"
- "@polkadot/rpc-provider": "npm:14.3.1"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- rxjs: "npm:^7.8.1"
- tslib: "npm:^2.8.0"
- checksum: 10c0/439223156cb243e5907655057367178562cdc4a30f960d67a61705b638cc017814055e0086a28e4b06b9b88e382302a7c17b1020b5a09f29dc37233ed2d7ffde
- languageName: node
- linkType: hard
-
"@polkadot/rpc-provider@npm:12.4.2, @polkadot/rpc-provider@npm:^12.0.2":
version: 12.4.2
resolution: "@polkadot/rpc-provider@npm:12.4.2"
@@ -2387,30 +2289,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/rpc-provider@npm:14.3.1, @polkadot/rpc-provider@npm:^14.3.1":
- version: 14.3.1
- resolution: "@polkadot/rpc-provider@npm:14.3.1"
- dependencies:
- "@polkadot/keyring": "npm:^13.2.3"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/types-support": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- "@polkadot/util-crypto": "npm:^13.2.3"
- "@polkadot/x-fetch": "npm:^13.2.3"
- "@polkadot/x-global": "npm:^13.2.3"
- "@polkadot/x-ws": "npm:^13.2.3"
- "@substrate/connect": "npm:0.8.11"
- eventemitter3: "npm:^5.0.1"
- mock-socket: "npm:^9.3.1"
- nock: "npm:^13.5.5"
- tslib: "npm:^2.8.0"
- dependenciesMeta:
- "@substrate/connect":
- optional: true
- checksum: 10c0/cab0c873be695678f4e2086dd0e7ba3e79e3aa20f447f941a60f160d3a8f52bfa340c54b10e0e0cd8bdcdd57d8effcab230d31b9bec1e6432aa92b19e881f41c
- languageName: node
- linkType: hard
-
"@polkadot/types-augment@npm:12.1.1":
version: 12.1.1
resolution: "@polkadot/types-augment@npm:12.1.1"
@@ -2435,18 +2313,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-augment@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/types-augment@npm:14.3.1"
- dependencies:
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- tslib: "npm:^2.8.0"
- checksum: 10c0/56192ce0bd656343196c46cea114ddf61488307ac8e4c7d578f6e41b877fc258765f1408ebe408ca9a0f7f64b16f661776fd76bb215f2d74c9690e4d4855de72
- languageName: node
- linkType: hard
-
"@polkadot/types-codec@npm:12.1.1":
version: 12.1.1
resolution: "@polkadot/types-codec@npm:12.1.1"
@@ -2469,17 +2335,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-codec@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/types-codec@npm:14.3.1"
- dependencies:
- "@polkadot/util": "npm:^13.2.3"
- "@polkadot/x-bigint": "npm:^13.2.3"
- tslib: "npm:^2.8.0"
- checksum: 10c0/e60353aa1218b460167d97447a7edbab527cceeb505e8206c065890622db5e95c6b1e703c69d75fd2dad410c8c598b0f721995f5d1af357420b461038526641b
- languageName: node
- linkType: hard
-
"@polkadot/types-create@npm:12.1.1":
version: 12.1.1
resolution: "@polkadot/types-create@npm:12.1.1"
@@ -2502,17 +2357,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-create@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/types-create@npm:14.3.1"
- dependencies:
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- tslib: "npm:^2.8.0"
- checksum: 10c0/18b07ebe2140010426f9c9c6648bd4e56911fc52465356c89b9969572db1c97a2f80bea985eb6f90d07bf1ca38b690050e36dc725ec5fcf4edeef85eabbe381a
- languageName: node
- linkType: hard
-
"@polkadot/types-known@npm:12.4.2":
version: 12.4.2
resolution: "@polkadot/types-known@npm:12.4.2"
@@ -2527,20 +2371,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-known@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/types-known@npm:14.3.1"
- dependencies:
- "@polkadot/networks": "npm:^13.2.3"
- "@polkadot/types": "npm:14.3.1"
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/types-create": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- tslib: "npm:^2.8.0"
- checksum: 10c0/c290b290b4856c77b15bc29a177caeaa6ce408b48c36a6c1fdf38160c5573a95bdd1476a1ad085dbe0853684deb4cd4c49fa67ee2d120809de8ec6e8005d08eb
- languageName: node
- linkType: hard
-
"@polkadot/types-support@npm:12.4.2":
version: 12.4.2
resolution: "@polkadot/types-support@npm:12.4.2"
@@ -2551,16 +2381,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types-support@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/types-support@npm:14.3.1"
- dependencies:
- "@polkadot/util": "npm:^13.2.3"
- tslib: "npm:^2.8.0"
- checksum: 10c0/fec80615ee0cdfa9d70a9e73d598de5b58f01f76557ac9c0060f9036bac1dd3695184ce8e4a81461a83988da2c28e5a8248a941fc891b2606a681f1ef218adfa
- languageName: node
- linkType: hard
-
"@polkadot/types@npm:12.1.1":
version: 12.1.1
resolution: "@polkadot/types@npm:12.1.1"
@@ -2593,22 +2413,6 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/types@npm:14.3.1":
- version: 14.3.1
- resolution: "@polkadot/types@npm:14.3.1"
- dependencies:
- "@polkadot/keyring": "npm:^13.2.3"
- "@polkadot/types-augment": "npm:14.3.1"
- "@polkadot/types-codec": "npm:14.3.1"
- "@polkadot/types-create": "npm:14.3.1"
- "@polkadot/util": "npm:^13.2.3"
- "@polkadot/util-crypto": "npm:^13.2.3"
- rxjs: "npm:^7.8.1"
- tslib: "npm:^2.8.0"
- checksum: 10c0/1cf0ad0f5f51cce1f9f3a5a694669fe327e3b8ec2c277dd7f0be74c7df1147b8713651c3a99ad8ac9a8c125a7681c2d6d05b6a7b0eaaa96f96a52bd4c61a8a47
- languageName: node
- linkType: hard
-
"@polkadot/util-crypto@npm:12.6.2, @polkadot/util-crypto@npm:^12.6.2":
version: 12.6.2
resolution: "@polkadot/util-crypto@npm:12.6.2"
@@ -2629,7 +2433,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/util-crypto@npm:13.2.3, @polkadot/util-crypto@npm:^13.0.2, @polkadot/util-crypto@npm:^13.2.3":
+"@polkadot/util-crypto@npm:13.2.3, @polkadot/util-crypto@npm:^13.0.2":
version: 13.2.3
resolution: "@polkadot/util-crypto@npm:13.2.3"
dependencies:
@@ -2769,7 +2573,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-bigint@npm:13.2.3, @polkadot/x-bigint@npm:^13.0.2, @polkadot/x-bigint@npm:^13.2.3":
+"@polkadot/x-bigint@npm:13.2.3, @polkadot/x-bigint@npm:^13.0.2":
version: 13.2.3
resolution: "@polkadot/x-bigint@npm:13.2.3"
dependencies:
@@ -2779,7 +2583,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-fetch@npm:^13.0.2, @polkadot/x-fetch@npm:^13.2.3":
+"@polkadot/x-fetch@npm:^13.0.2":
version: 13.2.3
resolution: "@polkadot/x-fetch@npm:13.2.3"
dependencies:
@@ -2799,7 +2603,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-global@npm:13.2.3, @polkadot/x-global@npm:^13.0.2, @polkadot/x-global@npm:^13.2.3":
+"@polkadot/x-global@npm:13.2.3, @polkadot/x-global@npm:^13.0.2":
version: 13.2.3
resolution: "@polkadot/x-global@npm:13.2.3"
dependencies:
@@ -2874,7 +2678,7 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot/x-ws@npm:^13.0.2, @polkadot/x-ws@npm:^13.2.3":
+"@polkadot/x-ws@npm:^13.0.2":
version: 13.2.3
resolution: "@polkadot/x-ws@npm:13.2.3"
dependencies:
@@ -4784,8 +4588,6 @@ __metadata:
"@polkadot-api/merkleize-metadata": "npm:^1.1.4"
"@polkadot-api/signers-common": "npm:^0.1.1"
"@polkadot-api/substrate-bindings": "npm:^0.9.3"
- "@polkadot/api": "npm:^14.3.1"
- "@polkadot/rpc-provider": "npm:^14.3.1"
"@polkawatch/ddp-client": "npm:^2.0.20"
"@substrate/connect": "npm:^2.0.1"
"@w3ux/extension-assets": "npm:^1.0.0-beta.1"
@@ -8920,7 +8722,7 @@ __metadata:
languageName: node
linkType: hard
-"nock@npm:^13.5.4, nock@npm:^13.5.5":
+"nock@npm:^13.5.4":
version: 13.5.6
resolution: "nock@npm:13.5.6"
dependencies:
From ae651b74c459544ed009b8e7984376749b54cb69 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 12:13:27 +0700
Subject: [PATCH 64/84] refactor BalanceTest
---
packages/app/src/modals/BalanceTest/index.tsx | 39 +-
yarn.lock | 526 +++++++++---------
2 files changed, 269 insertions(+), 296 deletions(-)
diff --git a/packages/app/src/modals/BalanceTest/index.tsx b/packages/app/src/modals/BalanceTest/index.tsx
index cf63a773b..7577ae2d3 100644
--- a/packages/app/src/modals/BalanceTest/index.tsx
+++ b/packages/app/src/modals/BalanceTest/index.tsx
@@ -2,51 +2,54 @@
// SPDX-License-Identifier: GPL-3.0-only
import { unitToPlanck } from '@w3ux/utils';
-import { useApi } from 'contexts/Api';
import { useOverlay } from 'kits/Overlay/Provider';
import { useTxMeta } from 'contexts/TxMeta';
import { useBatchCall } from 'hooks/useBatchCall';
-import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
import { Close } from 'library/Modal/Close';
-import { SubmitTx } from 'library/SubmitTx';
import { useEffect } from 'react';
import { useNetwork } from 'contexts/Network';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { ModalPadding } from 'kits/Overlay/structure/ModalPadding';
+import { ApiController } from 'controllers/Api';
+import { useSubmitExtrinsic } from 'hooks/useSubmitExtrinsic';
+import { SubmitTx } from 'library/SubmitTx';
export const BalanceTest = () => {
- const { api } = useApi();
const {
+ network,
networkData: { units },
} = useNetwork();
- const { activeAccount } = useActiveAccounts();
const { notEnoughFunds } = useTxMeta();
const { newBatchCall } = useBatchCall();
- const { setModalStatus, setModalResize } = useOverlay().modal;
+ const { activeAccount } = useActiveAccounts();
+ const { setModalResize, setModalStatus } = useOverlay().modal;
// tx to submit
const getTx = () => {
+ const { pApi } = ApiController.get(network);
+
const tx = null;
- if (!api || !activeAccount) {
+ if (!pApi || !activeAccount) {
return tx;
}
const txs = [
- api.tx.balances.transfer(
- {
- id: '1554u1a67ApEt5xmjbZwjgDNaVckbzB6cjRHWAQ1SpNkNxTd',
+ pApi.tx.Balances.transfer_keep_alive({
+ dest: {
+ type: 'Id',
+ value: '1554u1a67ApEt5xmjbZwjgDNaVckbzB6cjRHWAQ1SpNkNxTd',
},
- unitToPlanck('0.1', units).toString()
- ),
- api.tx.balances.transfer(
- {
- id: '1554u1a67ApEt5xmjbZwjgDNaVckbzB6cjRHWAQ1SpNkNxTd',
+ value: unitToPlanck('0.1', units).toString(),
+ }),
+ pApi.tx.Balances.transfer_keep_alive({
+ dest: {
+ type: 'Id',
+ value: '1554u1a67ApEt5xmjbZwjgDNaVckbzB6cjRHWAQ1SpNkNxTd',
},
- unitToPlanck('0.05', units).toString()
- ),
+ value: unitToPlanck('0.1', units).toString(),
+ }),
];
const batch = newBatchCall(txs, activeAccount);
-
return batch;
};
diff --git a/yarn.lock b/yarn.lock
index 05b7687aa..04ac921e5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -747,46 +747,46 @@ __metadata:
languageName: node
linkType: hard
-"@fortawesome/fontawesome-common-types@npm:6.6.0":
- version: 6.6.0
- resolution: "@fortawesome/fontawesome-common-types@npm:6.6.0"
- checksum: 10c0/f76e5959f6ce01355f599126a3a68facba578dc8ebb7ad40fbd22417b7056364a577c1887720ec9653d4efa5b704a01150f5064fc7de237d697fd80e3d9c83aa
+"@fortawesome/fontawesome-common-types@npm:6.7.1":
+ version: 6.7.1
+ resolution: "@fortawesome/fontawesome-common-types@npm:6.7.1"
+ checksum: 10c0/0345b896ad8df26fb823893ce0a405dd513e9ef34878dd7b94fbbbabe370379bf680a32199bcaaf7346acbcd2a10bf0072e305829b49e5d9b0bf1c5315d07c96
languageName: node
linkType: hard
"@fortawesome/fontawesome-svg-core@npm:^6.5.2":
- version: 6.6.0
- resolution: "@fortawesome/fontawesome-svg-core@npm:6.6.0"
+ version: 6.7.1
+ resolution: "@fortawesome/fontawesome-svg-core@npm:6.7.1"
dependencies:
- "@fortawesome/fontawesome-common-types": "npm:6.6.0"
- checksum: 10c0/38e2840791711524a3c57d9ea48a5a2e99da6fa3c657ba6beaad7ec3b8da31489a9e38f42b23d70584c75b579dc1ff8c67e075bc9789032278e4da54bb86ecfe
+ "@fortawesome/fontawesome-common-types": "npm:6.7.1"
+ checksum: 10c0/7a1dc40fc5ef380eb0f83d89dfcb26dc5b49f6a6545970e46e413d81dfa9764006a056cfcd49c2e8113dbd2c95d429db873710424a150e4a923b2496e11707ca
languageName: node
linkType: hard
"@fortawesome/free-brands-svg-icons@npm:^6.5.2":
- version: 6.6.0
- resolution: "@fortawesome/free-brands-svg-icons@npm:6.6.0"
+ version: 6.7.1
+ resolution: "@fortawesome/free-brands-svg-icons@npm:6.7.1"
dependencies:
- "@fortawesome/fontawesome-common-types": "npm:6.6.0"
- checksum: 10c0/1135a22ff274939da477496f550b6750a1b5fd0ddd0c09bddb1874f2c183a5c8edb519de2cebf6454b12a8457c3eec587bdb6f68e96140cceeb6d02c1ec35479
+ "@fortawesome/fontawesome-common-types": "npm:6.7.1"
+ checksum: 10c0/bd140ed872582300f7ed4b2af9348791cae38217ee0685ea34c135b00ce8db07da17b518464162a29d371f2f7177d3051b02535ca6b560bb15981ef34ef8e112
languageName: node
linkType: hard
"@fortawesome/free-regular-svg-icons@npm:^6.5.2":
- version: 6.6.0
- resolution: "@fortawesome/free-regular-svg-icons@npm:6.6.0"
+ version: 6.7.1
+ resolution: "@fortawesome/free-regular-svg-icons@npm:6.7.1"
dependencies:
- "@fortawesome/fontawesome-common-types": "npm:6.6.0"
- checksum: 10c0/c682a6d7c6bdce492eee5b15a6647f9c436ce04f337080b7061cc04a739b5eb95224f7cdc7d865cf08fea837d4d1b1541849a3183534956e176896a969220d45
+ "@fortawesome/fontawesome-common-types": "npm:6.7.1"
+ checksum: 10c0/6d770622cd6519835d8557a0a562c5f2f877527bb65671a6136a558ce61024bf7baaeb8e29420f29da4893b815c3af8173c6f45064bbcc040db613998d77502e
languageName: node
linkType: hard
"@fortawesome/free-solid-svg-icons@npm:^6.5.2":
- version: 6.6.0
- resolution: "@fortawesome/free-solid-svg-icons@npm:6.6.0"
+ version: 6.7.1
+ resolution: "@fortawesome/free-solid-svg-icons@npm:6.7.1"
dependencies:
- "@fortawesome/fontawesome-common-types": "npm:6.6.0"
- checksum: 10c0/34828d5e682c6f9d19e3a892ff8a390128fa7dc68768b11c727c11b6a05e5efc929206bfbec83e9d3ae0590a6f6ea22fd5e447fea647e560650f7f3ef1cff543
+ "@fortawesome/fontawesome-common-types": "npm:6.7.1"
+ checksum: 10c0/9b6e6ba383dfc456020b77a600edcccaf8131ebd472038bd6b6f2425f011c8c63c0a6049d798dc120512b9c5332043eb46bb815d9d55c56ebdf8ecc94afb0184
languageName: node
linkType: hard
@@ -1077,9 +1077,9 @@ __metadata:
linkType: hard
"@kurkle/color@npm:^0.3.0":
- version: 0.3.2
- resolution: "@kurkle/color@npm:0.3.2"
- checksum: 10c0/a9e8e3e35dcd59dec4dd4f0105919c05e24823a96347bcf152965c29e48d6290b66d5fb96c071875db752e10930724c48ce6d338fefbd65e0ce5082d5c78970e
+ version: 0.3.4
+ resolution: "@kurkle/color@npm:0.3.4"
+ checksum: 10c0/0e9fd55c614b005c5f0c4c755bca19ec0293bc7513b4ea3ec1725234f9c2fa81afbc78156baf555c8b9cb0d305619253c3f5bca016067daeebb3d00ebb4ea683
languageName: node
linkType: hard
@@ -1760,84 +1760,72 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/cli@npm:0.9.17":
- version: 0.9.17
- resolution: "@polkadot-api/cli@npm:0.9.17"
+"@polkadot-api/cli@npm:0.9.20":
+ version: 0.9.20
+ resolution: "@polkadot-api/cli@npm:0.9.20"
dependencies:
"@commander-js/extra-typings": "npm:^12.1.0"
- "@polkadot-api/codegen": "npm:0.12.7"
- "@polkadot-api/ink-contracts": "npm:0.2.0"
+ "@polkadot-api/codegen": "npm:0.12.8"
+ "@polkadot-api/ink-contracts": "npm:0.2.1"
"@polkadot-api/json-rpc-provider": "npm:0.0.4"
- "@polkadot-api/known-chains": "npm:0.5.6"
+ "@polkadot-api/known-chains": "npm:0.5.7"
"@polkadot-api/metadata-compatibility": "npm:0.1.11"
"@polkadot-api/observable-client": "npm:0.6.2"
"@polkadot-api/polkadot-sdk-compat": "npm:2.3.1"
- "@polkadot-api/sm-provider": "npm:0.1.5"
- "@polkadot-api/smoldot": "npm:0.3.5"
+ "@polkadot-api/sm-provider": "npm:0.1.7"
+ "@polkadot-api/smoldot": "npm:0.3.7"
"@polkadot-api/substrate-bindings": "npm:0.9.3"
"@polkadot-api/substrate-client": "npm:0.3.0"
"@polkadot-api/utils": "npm:0.1.2"
- "@polkadot-api/wasm-executor": "npm:^0.1.1"
- "@polkadot-api/ws-provider": "npm:0.3.4"
- "@types/node": "npm:^22.2.0"
+ "@polkadot-api/wasm-executor": "npm:^0.1.2"
+ "@polkadot-api/ws-provider": "npm:0.3.6"
+ "@types/node": "npm:^22.9.0"
commander: "npm:^12.1.0"
- execa: "npm:^9.3.0"
+ execa: "npm:^9.5.1"
fs.promises.exists: "npm:^1.1.4"
- ora: "npm:^8.0.1"
+ ora: "npm:^8.1.1"
read-pkg: "npm:^9.0.1"
rxjs: "npm:^7.8.1"
tsc-prog: "npm:^2.3.0"
- tsup: "npm:^8.2.4"
- typescript: "npm:^5.5.4"
+ tsup: "npm:^8.3.5"
+ typescript: "npm:^5.6.3"
write-package: "npm:^7.1.0"
bin:
papi: dist/main.js
polkadot-api: dist/main.js
- checksum: 10c0/0bdbe91a11e07b0dcc730594c8adfe69fe7e522e7824f07feac51203dec1696e7ba050df209880567467b2813d20559ed85e23a62f71a179c348369f59574265
+ checksum: 10c0/579b3dbc6c291a80aa4963745db41f2879727c4c811282bea8ba07e45ee130a524f2b9bcd142b9af3aed68740dbdf798a0f9e15a2167d94cf35459f96b7855da
languageName: node
linkType: hard
-"@polkadot-api/codegen@npm:0.12.7":
- version: 0.12.7
- resolution: "@polkadot-api/codegen@npm:0.12.7"
+"@polkadot-api/codegen@npm:0.12.8":
+ version: 0.12.8
+ resolution: "@polkadot-api/codegen@npm:0.12.8"
dependencies:
- "@polkadot-api/ink-contracts": "npm:0.1.2"
+ "@polkadot-api/ink-contracts": "npm:0.2.1"
"@polkadot-api/metadata-builders": "npm:0.9.1"
"@polkadot-api/metadata-compatibility": "npm:0.1.11"
"@polkadot-api/substrate-bindings": "npm:0.9.3"
"@polkadot-api/utils": "npm:0.1.2"
- checksum: 10c0/3330e74627123d24e0b9c572c172f832060d55b84e87986c8712ee17d9b84e299d90c3f06ff2b8aa1561a21219492bddce723e4c84e16c570f262028aea32333
- languageName: node
- linkType: hard
-
-"@polkadot-api/ink-contracts@npm:0.1.2":
- version: 0.1.2
- resolution: "@polkadot-api/ink-contracts@npm:0.1.2"
- dependencies:
- "@polkadot-api/metadata-builders": "npm:0.9.1"
- "@polkadot-api/substrate-bindings": "npm:0.9.3"
- "@polkadot-api/utils": "npm:0.1.2"
- scale-ts: "npm:^1.6.1"
- checksum: 10c0/334203d4c981b691c8f0215746787a7664186c2947ba89818e58034643ab4f552ead612f8cf0b1f6cf29ad13696433717f01a75fde00fd6cd7a90cf0492e61f1
+ checksum: 10c0/18f1be81133ff07eb2ea6931bb1091ee5fde19f6943042d98b2126c168d870740202dc236c4783767b00ff35e40040e09ebc28d12ed4075228bfdadbf5b9d3f0
languageName: node
linkType: hard
-"@polkadot-api/ink-contracts@npm:0.2.0":
- version: 0.2.0
- resolution: "@polkadot-api/ink-contracts@npm:0.2.0"
+"@polkadot-api/ink-contracts@npm:0.2.1":
+ version: 0.2.1
+ resolution: "@polkadot-api/ink-contracts@npm:0.2.1"
dependencies:
"@polkadot-api/metadata-builders": "npm:0.9.1"
"@polkadot-api/substrate-bindings": "npm:0.9.3"
"@polkadot-api/utils": "npm:0.1.2"
scale-ts: "npm:^1.6.1"
- checksum: 10c0/c5f2457452047c0511bc3092cf61fbe1aafdc665fe5a8b60227fce57f587effea3e1f8d145ae3e6db1631a84286f40847cbf2c74f4f580e643151d2f09b92676
+ checksum: 10c0/a6df3a780d41d577832576790beb355132d86f8089d1886fc5e78250e3de3556ade9571e71f893b93eebb3476f8c82804eb477d626ed26c993dc2ea3b4d9ef20
languageName: node
linkType: hard
-"@polkadot-api/json-rpc-provider-proxy@npm:0.2.3":
- version: 0.2.3
- resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.2.3"
- checksum: 10c0/eeaa46751fba879c03bde24a06a9aa4941bd901d166e1c49ae8d3596b7c6e8a868d4f25ba75c4a9761283953c2511057a51dd3ae27e4c0d7823d55f55af384b9
+"@polkadot-api/json-rpc-provider-proxy@npm:0.2.4":
+ version: 0.2.4
+ resolution: "@polkadot-api/json-rpc-provider-proxy@npm:0.2.4"
+ checksum: 10c0/bf99d5a27e02dc5b3641d4c17ec28d7ac72b7ad077e99a311f3c2709000957429321ae93926c941024539c521a118d45251fc8ab3f8fc11334e1385a2f8908ff
languageName: node
linkType: hard
@@ -1862,10 +1850,10 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/known-chains@npm:0.5.6":
- version: 0.5.6
- resolution: "@polkadot-api/known-chains@npm:0.5.6"
- checksum: 10c0/1767760ecdf834540290bdde8ab823907121b0ee3fee071bb393f00625b419299168c71cbcfaa6e6af67789cc5f4e4083a0020c955540b5f379b120895b44556
+"@polkadot-api/known-chains@npm:0.5.7":
+ version: 0.5.7
+ resolution: "@polkadot-api/known-chains@npm:0.5.7"
+ checksum: 10c0/5ba499e58f0066346a48bda459b23570c849fb267a10c8a23494661c563ea7763b560d4d3fa95283b9cb6767d1a1af651d23c94ac7550050d2f5f874569e29d1
languageName: node
linkType: hard
@@ -2001,25 +1989,25 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/sm-provider@npm:0.1.5":
- version: 0.1.5
- resolution: "@polkadot-api/sm-provider@npm:0.1.5"
+"@polkadot-api/sm-provider@npm:0.1.7":
+ version: 0.1.7
+ resolution: "@polkadot-api/sm-provider@npm:0.1.7"
dependencies:
"@polkadot-api/json-rpc-provider": "npm:0.0.4"
- "@polkadot-api/json-rpc-provider-proxy": "npm:0.2.3"
+ "@polkadot-api/json-rpc-provider-proxy": "npm:0.2.4"
peerDependencies:
"@polkadot-api/smoldot": ">=0.3"
- checksum: 10c0/d87dfc11d5d491c0bdb35e2a788641c8e1ec738d47885c1929c29d22ea03eaaf14a7ea355507b8817a42f9d37f0ae265ee138e6fd46618ca47cc6622046a302b
+ checksum: 10c0/91a1b8cc054f5b8f5ec25a40d9bc876ad5e9138a9801b22a2e4f6bf396ed584956cff0de7349d9b435fe5c04bad9137e59edcb6960943b9126e7262c9a0d8740
languageName: node
linkType: hard
-"@polkadot-api/smoldot@npm:0.3.5":
- version: 0.3.5
- resolution: "@polkadot-api/smoldot@npm:0.3.5"
+"@polkadot-api/smoldot@npm:0.3.7":
+ version: 0.3.7
+ resolution: "@polkadot-api/smoldot@npm:0.3.7"
dependencies:
- "@types/node": "npm:^22.2.0"
- smoldot: "npm:2.0.31"
- checksum: 10c0/a9658a06bf4a3bcb5127dcf3a58adf732c43be4c683cdd7054dadfb55122f32ce990aab866deb0a572340faadfdf9813ef2f938ae220be58628be67eeb14342d
+ "@types/node": "npm:^22.9.0"
+ smoldot: "npm:2.0.33"
+ checksum: 10c0/edd2e4b31a3f43231e86dc9452c8cf9c126858c48539d35d5f01146a6958db8f530dc01a9aaf01ffb8b7f0b3750cdc16223df80d548e212955de889defced114
languageName: node
linkType: hard
@@ -2081,21 +2069,21 @@ __metadata:
languageName: node
linkType: hard
-"@polkadot-api/wasm-executor@npm:^0.1.1":
+"@polkadot-api/wasm-executor@npm:^0.1.2":
version: 0.1.2
resolution: "@polkadot-api/wasm-executor@npm:0.1.2"
checksum: 10c0/0577111cf7ee12e1606ba863385f50670f2d073e9032efd8365e578f03f4a8b01e699641e19b2aec15e36832aa3b6b0724951fa84d23e87492d0532f55e291bf
languageName: node
linkType: hard
-"@polkadot-api/ws-provider@npm:0.3.4":
- version: 0.3.4
- resolution: "@polkadot-api/ws-provider@npm:0.3.4"
+"@polkadot-api/ws-provider@npm:0.3.6":
+ version: 0.3.6
+ resolution: "@polkadot-api/ws-provider@npm:0.3.6"
dependencies:
"@polkadot-api/json-rpc-provider": "npm:0.0.4"
- "@polkadot-api/json-rpc-provider-proxy": "npm:0.2.3"
+ "@polkadot-api/json-rpc-provider-proxy": "npm:0.2.4"
ws: "npm:^8.18.0"
- checksum: 10c0/39243a8f1545dd8191c62f43ee05e2450b5a7758adfe974f2d4a965546ea5001f19ff7ca14c87d1655dba1526ad08f8118a2cc6597f53d3a3172860b5da4d10d
+ checksum: 10c0/902c599ef02ddc3564cd4517aa3235262de1523a6879f81f94d73c90c260990fd595db7eacb2184670d9aa811eddc5eb346e78f74a60677846d991457e014ce9
languageName: node
linkType: hard
@@ -2792,128 +2780,128 @@ __metadata:
languageName: node
linkType: hard
-"@rollup/rollup-android-arm-eabi@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-android-arm-eabi@npm:4.26.0"
+"@rollup/rollup-android-arm-eabi@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-android-arm-eabi@npm:4.27.3"
conditions: os=android & cpu=arm
languageName: node
linkType: hard
-"@rollup/rollup-android-arm64@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-android-arm64@npm:4.26.0"
+"@rollup/rollup-android-arm64@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-android-arm64@npm:4.27.3"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-darwin-arm64@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-darwin-arm64@npm:4.26.0"
+"@rollup/rollup-darwin-arm64@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-darwin-arm64@npm:4.27.3"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-darwin-x64@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-darwin-x64@npm:4.26.0"
+"@rollup/rollup-darwin-x64@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-darwin-x64@npm:4.27.3"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
-"@rollup/rollup-freebsd-arm64@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-freebsd-arm64@npm:4.26.0"
+"@rollup/rollup-freebsd-arm64@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-freebsd-arm64@npm:4.27.3"
conditions: os=freebsd & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-freebsd-x64@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-freebsd-x64@npm:4.26.0"
+"@rollup/rollup-freebsd-x64@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-freebsd-x64@npm:4.27.3"
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm-gnueabihf@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.26.0"
+"@rollup/rollup-linux-arm-gnueabihf@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.27.3"
conditions: os=linux & cpu=arm & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm-musleabihf@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.26.0"
+"@rollup/rollup-linux-arm-musleabihf@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.27.3"
conditions: os=linux & cpu=arm & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm64-gnu@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.26.0"
+"@rollup/rollup-linux-arm64-gnu@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.27.3"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-arm64-musl@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-arm64-musl@npm:4.26.0"
+"@rollup/rollup-linux-arm64-musl@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-arm64-musl@npm:4.27.3"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-linux-powerpc64le-gnu@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.26.0"
+"@rollup/rollup-linux-powerpc64le-gnu@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.27.3"
conditions: os=linux & cpu=ppc64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-riscv64-gnu@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.26.0"
+"@rollup/rollup-linux-riscv64-gnu@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.27.3"
conditions: os=linux & cpu=riscv64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-s390x-gnu@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.26.0"
+"@rollup/rollup-linux-s390x-gnu@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.27.3"
conditions: os=linux & cpu=s390x & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-x64-gnu@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-x64-gnu@npm:4.26.0"
+"@rollup/rollup-linux-x64-gnu@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-x64-gnu@npm:4.27.3"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
-"@rollup/rollup-linux-x64-musl@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-linux-x64-musl@npm:4.26.0"
+"@rollup/rollup-linux-x64-musl@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-linux-x64-musl@npm:4.27.3"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
-"@rollup/rollup-win32-arm64-msvc@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.26.0"
+"@rollup/rollup-win32-arm64-msvc@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.27.3"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
-"@rollup/rollup-win32-ia32-msvc@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.26.0"
+"@rollup/rollup-win32-ia32-msvc@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.27.3"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
-"@rollup/rollup-win32-x64-msvc@npm:4.26.0":
- version: 4.26.0
- resolution: "@rollup/rollup-win32-x64-msvc@npm:4.26.0"
+"@rollup/rollup-win32-x64-msvc@npm:4.27.3":
+ version: 4.27.3
+ resolution: "@rollup/rollup-win32-x64-msvc@npm:4.27.3"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
@@ -2946,9 +2934,9 @@ __metadata:
linkType: hard
"@safe-global/safe-gateway-typescript-sdk@npm:^3.5.3":
- version: 3.22.2
- resolution: "@safe-global/safe-gateway-typescript-sdk@npm:3.22.2"
- checksum: 10c0/4c61c6bc1e720ceb98e7812ef060e40120e130c385f1ac8012a99155179b0651e12f608e053c9e4d1d7917881920e9e3b15c3c90805f9bbb7f28d80b13d04381
+ version: 3.22.3
+ resolution: "@safe-global/safe-gateway-typescript-sdk@npm:3.22.3"
+ checksum: 10c0/17cb09945e845556332f65785f1aa6a2d4b7c319a87f6fde48263a88e6b2aeaa6f9bb82b4f12a471d1c6a5f2d03465d2ae34a7730d790ab51349d2039aacfa37
languageName: node
linkType: hard
@@ -3528,11 +3516,11 @@ __metadata:
linkType: hard
"@swc/types@npm:^0.1.15":
- version: 0.1.15
- resolution: "@swc/types@npm:0.1.15"
+ version: 0.1.16
+ resolution: "@swc/types@npm:0.1.16"
dependencies:
"@swc/counter": "npm:^0.1.3"
- checksum: 10c0/82bcfa64e53c6c93ae162fe9e491e5f300227fad6f110e32d9718e5a0e29586bc79c516234f6eccbe5ccd7ed72b514a21f03196a54408cf1b7b47c072fad44f0
+ checksum: 10c0/ca079125ef4c619a4ae908a9d6b99e526e0e21d54443585da9904e9e67a3e7320189843639c6e4435d807dfae5837ab3083a18e86f698e1decf00ecc277ab0ec
languageName: node
linkType: hard
@@ -3624,12 +3612,12 @@ __metadata:
languageName: node
linkType: hard
-"@types/node@npm:*, @types/node@npm:^22.2.0":
- version: 22.9.0
- resolution: "@types/node@npm:22.9.0"
+"@types/node@npm:*, @types/node@npm:^22.9.0":
+ version: 22.9.1
+ resolution: "@types/node@npm:22.9.1"
dependencies:
undici-types: "npm:~6.19.8"
- checksum: 10c0/3f46cbe0a49bab4ba30494025e4c8a6e699b98ac922857aa1f0209ce11a1313ee46e6808b8f13fe5b8b960a9d7796b77c8d542ad4e9810e85ef897d5593b5d51
+ checksum: 10c0/ea489ae603aa8874e4e88980aab6f2dad09c755da779c88dd142983bfe9609803c89415ca7781f723072934066f63daf2b3339ef084a8ad1a8079cf3958be243
languageName: node
linkType: hard
@@ -3972,7 +3960,7 @@ __metadata:
languageName: node
linkType: hard
-"@w3ux/utils@npm:^1.1.1-beta.11":
+"@w3ux/utils@npm:^1.1.1-beta.11, @w3ux/utils@npm:^1.1.1-beta.9":
version: 1.1.1-beta.11
resolution: "@w3ux/utils@npm:1.1.1-beta.11"
dependencies:
@@ -3981,15 +3969,6 @@ __metadata:
languageName: node
linkType: hard
-"@w3ux/utils@npm:^1.1.1-beta.9":
- version: 1.1.1-beta.9
- resolution: "@w3ux/utils@npm:1.1.1-beta.9"
- dependencies:
- "@polkadot-api/substrate-bindings": "npm:^0.9.3"
- checksum: 10c0/b18cf8274d43cf3419e8b47fc822164653da7a48a83a6eb84820b9fe14386e5f167ad1f634bfddac938f472839bc605e9bb04e8a88cfd12223b5b40b24730934
- languageName: node
- linkType: hard
-
"@w3ux/validator-assets@npm:^0.2.0":
version: 0.2.0
resolution: "@w3ux/validator-assets@npm:0.2.0"
@@ -3999,9 +3978,9 @@ __metadata:
languageName: node
linkType: hard
-"@wagmi/connectors@npm:5.3.10":
- version: 5.3.10
- resolution: "@wagmi/connectors@npm:5.3.10"
+"@wagmi/connectors@npm:5.5.0":
+ version: 5.5.0
+ resolution: "@wagmi/connectors@npm:5.5.0"
dependencies:
"@coinbase/wallet-sdk": "npm:4.2.3"
"@metamask/sdk": "npm:0.30.1"
@@ -4010,19 +3989,19 @@ __metadata:
"@walletconnect/ethereum-provider": "npm:2.17.0"
cbw-sdk: "npm:@coinbase/wallet-sdk@3.9.3"
peerDependencies:
- "@wagmi/core": 2.14.6
+ "@wagmi/core": 2.15.0
typescript: ">=5.0.4"
viem: 2.x
peerDependenciesMeta:
typescript:
optional: true
- checksum: 10c0/683affe0fe0a319fa7e84d9eca6069a12fed288c9caea589ef6547af530111a18538546babc15719b023cbbf1f324ccc59c668163aed7cc21ab84bb906f84cca
+ checksum: 10c0/bbf2e74b3f35725a5ea410763b4d7cbe41dab55bffa55204cf42c20d25a3368480223f018497c8493137c0fe0df28810e94008da7c379ec859e544cb98c95553
languageName: node
linkType: hard
-"@wagmi/core@npm:2.14.6":
- version: 2.14.6
- resolution: "@wagmi/core@npm:2.14.6"
+"@wagmi/core@npm:2.15.0":
+ version: 2.15.0
+ resolution: "@wagmi/core@npm:2.15.0"
dependencies:
eventemitter3: "npm:5.0.1"
mipd: "npm:0.0.7"
@@ -4036,7 +4015,7 @@ __metadata:
optional: true
typescript:
optional: true
- checksum: 10c0/bc79ba678f00da5e769526875698e9dc1464fc650f3db27ecf9865b78f0690b7006bb36b0ea0acf6deb9ea5d5a84d343fc8ec6efaa9e9a73868ddca9a8eb046e
+ checksum: 10c0/9f8889e6b58677287799f4faccf6910b57d5ea8bdb12a6a4faf930a6a8c45dc3cb641e4eba697011ad195601a33fe30aea1a700d6dbc853de5138e3268f1cfb4
languageName: node
linkType: hard
@@ -4384,15 +4363,6 @@ __metadata:
languageName: node
linkType: hard
-"@wry/trie@npm:^0.4.3":
- version: 0.4.3
- resolution: "@wry/trie@npm:0.4.3"
- dependencies:
- tslib: "npm:^2.3.0"
- checksum: 10c0/1a14edba595b1967d0cf38208c2660b2952a8e8a649bb669b67907df48f602c7f2acbe16c1e1b115afa7d7effb9f1a4dbde38eef16ee92e7521a511262a53281
- languageName: node
- linkType: hard
-
"@wry/trie@npm:^0.5.0":
version: 0.5.0
resolution: "@wry/trie@npm:0.5.0"
@@ -5038,9 +5008,9 @@ __metadata:
linkType: hard
"caniuse-lite@npm:^1.0.30001669":
- version: 1.0.30001680
- resolution: "caniuse-lite@npm:1.0.30001680"
- checksum: 10c0/11a4e7f6f5d5f965cfd4b7dc4aef34e12a26e99647f02b5ac9fd7f7670845473b95ada416a785473237e4b1b67281f7b043c8736c85b77097f6b697e8950b15f
+ version: 1.0.30001682
+ resolution: "caniuse-lite@npm:1.0.30001682"
+ checksum: 10c0/de9d8bc08e293f8bf6e98e9035055920a75042a655c6abacbf0a4af5ec77882d26df4489721a7f723559c817b13f3fee86b35e827ee2383a5cdf7fb41c60dcd0
languageName: node
linkType: hard
@@ -5400,13 +5370,13 @@ __metadata:
linkType: hard
"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3":
- version: 7.0.5
- resolution: "cross-spawn@npm:7.0.5"
+ version: 7.0.6
+ resolution: "cross-spawn@npm:7.0.6"
dependencies:
path-key: "npm:^3.1.0"
shebang-command: "npm:^2.0.0"
which: "npm:^2.0.1"
- checksum: 10c0/aa82ce7ac0814a27e6f2b738c5a7cf1fa21a3558a1e42df449fc96541ba3ba731e4d3ecffa4435348808a86212f287c6f20a1ee551ef1ff95d01cfec5f434944
+ checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1
languageName: node
linkType: hard
@@ -5716,21 +5686,21 @@ __metadata:
linkType: hard
"eciesjs@npm:^0.4.8":
- version: 0.4.11
- resolution: "eciesjs@npm:0.4.11"
+ version: 0.4.12
+ resolution: "eciesjs@npm:0.4.12"
dependencies:
"@ecies/ciphers": "npm:^0.2.1"
"@noble/ciphers": "npm:^1.0.0"
"@noble/curves": "npm:^1.6.0"
"@noble/hashes": "npm:^1.5.0"
- checksum: 10c0/3b707a46313d6a7629b37e6f86bb72b038f3acef994b270e5683644278bdc2278a4b125beb6a010ba2a3944c2ada469a7d3e87ff7cbd50b808f191c03530ea54
+ checksum: 10c0/c2fc1afc9cfe79e89c13f82d7b9441d503b7cacf99b6cd221d75acf78678fde401608b7c49fd54965b5a83c6d36d04b510b78c3dc1499d8bc8cfcaea84666aab
languageName: node
linkType: hard
"electron-to-chromium@npm:^1.5.41":
- version: 1.5.57
- resolution: "electron-to-chromium@npm:1.5.57"
- checksum: 10c0/42b969681985016be6069ae68cf29e84ba3f2191fcb7f9d3355e83e81da8dbd100e4b5c9d69b88637003e06dc1860125a50332ec0caee49fd9c2c4ab62feb288
+ version: 1.5.63
+ resolution: "electron-to-chromium@npm:1.5.63"
+ checksum: 10c0/fe1b175805309b04e5a2242c3168f22543e5369aed01fceedfe0f0eafe3931e8609d8a140e527394b314cfe64d581913aba6f1d3c72c23069c7d8241e5dfa4ef
languageName: node
linkType: hard
@@ -5865,8 +5835,8 @@ __metadata:
linkType: hard
"es-abstract@npm:^1.17.5, es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3":
- version: 1.23.4
- resolution: "es-abstract@npm:1.23.4"
+ version: 1.23.5
+ resolution: "es-abstract@npm:1.23.5"
dependencies:
array-buffer-byte-length: "npm:^1.0.1"
arraybuffer.prototype.slice: "npm:^1.0.3"
@@ -5914,7 +5884,7 @@ __metadata:
typed-array-length: "npm:^1.0.6"
unbox-primitive: "npm:^1.0.2"
which-typed-array: "npm:^1.1.15"
- checksum: 10c0/70c56ec479d57e63387f561bb50c80587f4a52010868787e3d4b4f95301edf5ba98d70ffd0ba56eb4722c48c578870ff2a8825236a948cfa483f76015d134acb
+ checksum: 10c0/1f6f91da9cf7ee2c81652d57d3046621d598654d1d1b05c1578bafe5c4c2d3d69513901679bdca2de589f620666ec21de337e4935cec108a4ed0871d5ef04a5d
languageName: node
linkType: hard
@@ -6592,7 +6562,7 @@ __metadata:
languageName: node
linkType: hard
-"execa@npm:^9.3.0":
+"execa@npm:^9.5.1":
version: 9.5.1
resolution: "execa@npm:9.5.1"
dependencies:
@@ -6788,9 +6758,9 @@ __metadata:
linkType: hard
"flatted@npm:^3.2.9":
- version: 3.3.1
- resolution: "flatted@npm:3.3.1"
- checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf
+ version: 3.3.2
+ resolution: "flatted@npm:3.3.2"
+ checksum: 10c0/24cc735e74d593b6c767fe04f2ef369abe15b62f6906158079b9874bdb3ee5ae7110bb75042e70cd3f99d409d766f357caf78d5ecee9780206f5fdc5edbad334
languageName: node
linkType: hard
@@ -6844,8 +6814,8 @@ __metadata:
linkType: hard
"framer-motion@npm:^11.11.1":
- version: 11.11.15
- resolution: "framer-motion@npm:11.11.15"
+ version: 11.11.17
+ resolution: "framer-motion@npm:11.11.17"
dependencies:
tslib: "npm:^2.4.0"
peerDependencies:
@@ -6859,7 +6829,7 @@ __metadata:
optional: true
react-dom:
optional: true
- checksum: 10c0/515d1f758ebf8c7257f80586fe459acbb77f323e7a2f3e8b20bf53023960f5e54b1cf364b39fa2ded2ec0558c66e78c681b3903cfac11fefdb51efcfaff21443
+ checksum: 10c0/4ec88a568e636c5409a238668770a7d0237270b4b58fdf27d0cab1f9094a4fdd22d25d827a1bba51e52f01e9d2db65544b32a5feb8eff9a63c8798f2e64677d0
languageName: node
linkType: hard
@@ -7390,11 +7360,11 @@ __metadata:
linkType: hard
"i18next@npm:^23.11.5":
- version: 23.16.5
- resolution: "i18next@npm:23.16.5"
+ version: 23.16.8
+ resolution: "i18next@npm:23.16.8"
dependencies:
"@babel/runtime": "npm:^7.23.2"
- checksum: 10c0/4f926c09dc1087041084dbbfb8307bf2fdba1981069dece1c563577ca8a38a23ebfadf4d1c50c4091b640a8c8bf81d9cd008bd3e587bd452a6b9c728d5065346
+ checksum: 10c0/57d249191e8a39bbbbe190cfa2e2bb651d0198e14444fe80453d3df8d02927de3c147c77724e9ae6c72fa241898cd761e3fdcd55d053db373471f1ac084bf345
languageName: node
linkType: hard
@@ -8257,12 +8227,12 @@ __metadata:
linkType: hard
"local-pkg@npm:^0.5.0":
- version: 0.5.0
- resolution: "local-pkg@npm:0.5.0"
+ version: 0.5.1
+ resolution: "local-pkg@npm:0.5.1"
dependencies:
- mlly: "npm:^1.4.2"
- pkg-types: "npm:^1.0.3"
- checksum: 10c0/f61cbd00d7689f275558b1a45c7ff2a3ddf8472654123ed880215677b9adfa729f1081e50c27ffb415cdb9fa706fb755fec5e23cdd965be375c8059e87ff1cc9
+ mlly: "npm:^1.7.3"
+ pkg-types: "npm:^1.2.1"
+ checksum: 10c0/ade8346f1dc04875921461adee3c40774b00d4b74095261222ebd4d5fd0a444676e36e325f76760f21af6a60bc82480e154909b54d2d9f7173671e36dacf1808
languageName: node
linkType: hard
@@ -8382,11 +8352,11 @@ __metadata:
linkType: hard
"magic-string@npm:^0.30.5":
- version: 0.30.12
- resolution: "magic-string@npm:0.30.12"
+ version: 0.30.13
+ resolution: "magic-string@npm:0.30.13"
dependencies:
"@jridgewell/sourcemap-codec": "npm:^1.5.0"
- checksum: 10c0/469f457d18af37dfcca8617086ea8a65bcd8b60ba8a1182cb024ce43e470ace3c9d1cb6bee58d3b311768fb16bc27bd50bdeebcaa63dadd0fd46cac4d2e11d5f
+ checksum: 10c0/a275faeca1564c545019b4742c38a42ca80226c8c9e0805c32d1a1cc58b0e6ff7bbd914ed885fd10043858a7da0f732cb8f49c8975c3ecebde9cad4b57db5115
languageName: node
linkType: hard
@@ -8624,7 +8594,7 @@ __metadata:
languageName: node
linkType: hard
-"mlly@npm:^1.4.2, mlly@npm:^1.7.1, mlly@npm:^1.7.2":
+"mlly@npm:^1.7.1, mlly@npm:^1.7.2, mlly@npm:^1.7.3":
version: 1.7.3
resolution: "mlly@npm:1.7.3"
dependencies:
@@ -8798,13 +8768,13 @@ __metadata:
linkType: hard
"node-gyp-build@npm:^4.2.0, node-gyp-build@npm:^4.3.0":
- version: 4.8.3
- resolution: "node-gyp-build@npm:4.8.3"
+ version: 4.8.4
+ resolution: "node-gyp-build@npm:4.8.4"
bin:
node-gyp-build: bin.js
node-gyp-build-optional: optional.js
node-gyp-build-test: build-test.js
- checksum: 10c0/a7f43c4128d817db80bb0884f631121449ac586b4a3e708eab0db6fcb7fa0d2e66f6d7d4ee1f49469409de4a9b2e413926befe2dce70b850c6c583a3bbe228d2
+ checksum: 10c0/444e189907ece2081fe60e75368784f7782cfddb554b60123743dfb89509df89f1f29c03bbfa16b3a3e0be3f48799a4783f487da6203245fa5bed239ba7407e1
languageName: node
linkType: hard
@@ -9045,14 +9015,14 @@ __metadata:
linkType: hard
"optimism@npm:^0.18.0":
- version: 0.18.0
- resolution: "optimism@npm:0.18.0"
+ version: 0.18.1
+ resolution: "optimism@npm:0.18.1"
dependencies:
"@wry/caches": "npm:^1.0.0"
"@wry/context": "npm:^0.7.0"
- "@wry/trie": "npm:^0.4.3"
+ "@wry/trie": "npm:^0.5.0"
tslib: "npm:^2.3.0"
- checksum: 10c0/8e97c6d660cb80cf5f444209b9dd29ee6951fa7b344d4c4fc6d4aaf0ad0710dddaf834d0f5d7211b3658b15ef6c6a22cbcb98c7a8121e3fee9666fe0fd62d876
+ checksum: 10c0/1c1cd065d306de2220c6a2bdd8701cb7f9aadace36a9f16d6e02db2bee23b0291f15a1219b92cde5c66d816bd33dca876dfdcdbad04b4cf9b2a7fc5a1a221e77
languageName: node
linkType: hard
@@ -9070,7 +9040,7 @@ __metadata:
languageName: node
linkType: hard
-"ora@npm:^8.0.1":
+"ora@npm:^8.1.1":
version: 8.1.1
resolution: "ora@npm:8.1.1"
dependencies:
@@ -9367,7 +9337,7 @@ __metadata:
languageName: node
linkType: hard
-"pkg-types@npm:^1.0.3, pkg-types@npm:^1.2.1":
+"pkg-types@npm:^1.2.1":
version: 1.2.1
resolution: "pkg-types@npm:1.2.1"
dependencies:
@@ -9395,13 +9365,13 @@ __metadata:
linkType: hard
"polkadot-api@npm:^1.7.3":
- version: 1.7.3
- resolution: "polkadot-api@npm:1.7.3"
+ version: 1.7.6
+ resolution: "polkadot-api@npm:1.7.6"
dependencies:
- "@polkadot-api/cli": "npm:0.9.17"
- "@polkadot-api/ink-contracts": "npm:0.2.0"
+ "@polkadot-api/cli": "npm:0.9.20"
+ "@polkadot-api/ink-contracts": "npm:0.2.1"
"@polkadot-api/json-rpc-provider": "npm:0.0.4"
- "@polkadot-api/known-chains": "npm:0.5.6"
+ "@polkadot-api/known-chains": "npm:0.5.7"
"@polkadot-api/logs-provider": "npm:0.0.6"
"@polkadot-api/metadata-builders": "npm:0.9.1"
"@polkadot-api/metadata-compatibility": "npm:0.1.11"
@@ -9410,18 +9380,18 @@ __metadata:
"@polkadot-api/polkadot-sdk-compat": "npm:2.3.1"
"@polkadot-api/polkadot-signer": "npm:0.1.6"
"@polkadot-api/signer": "npm:0.1.10"
- "@polkadot-api/sm-provider": "npm:0.1.5"
- "@polkadot-api/smoldot": "npm:0.3.5"
+ "@polkadot-api/sm-provider": "npm:0.1.7"
+ "@polkadot-api/smoldot": "npm:0.3.7"
"@polkadot-api/substrate-bindings": "npm:0.9.3"
"@polkadot-api/substrate-client": "npm:0.3.0"
"@polkadot-api/utils": "npm:0.1.2"
- "@polkadot-api/ws-provider": "npm:0.3.4"
+ "@polkadot-api/ws-provider": "npm:0.3.6"
peerDependencies:
rxjs: ">=7.8.0"
bin:
papi: bin/cli.mjs
polkadot-api: bin/cli.mjs
- checksum: 10c0/ac430cd00d51308f65f3f8a1d7b405d3d1d86726c47481dfa2cfb2c08c36dda3cb51f0a880a00c7fa677e84bae3385de91e3da6627492fad89848b5a3e94b6fa
+ checksum: 10c0/caa2df461f2a252aeb8b1b9076bc096a4c6952015a88ac004defc2aac2ea385349767db5394e6a98fef8fdf28eaadbfbcc1914fbacc14d108923f13ed6cf1a12
languageName: node
linkType: hard
@@ -9583,11 +9553,11 @@ __metadata:
linkType: hard
"pretty-ms@npm:^9.0.0":
- version: 9.1.0
- resolution: "pretty-ms@npm:9.1.0"
+ version: 9.2.0
+ resolution: "pretty-ms@npm:9.2.0"
dependencies:
parse-ms: "npm:^4.0.0"
- checksum: 10c0/fd111aad8800a04dfd654e6016da69bdaa6fc6a4c280f8e727cffd8b5960558e94942f1a94d4aa6e4d179561a0fbb0366a9ebe0ccefbbb0f8ff853b129cdefb9
+ checksum: 10c0/ab6d066f90e9f77020426986e1b018369f41575674544c539aabec2e63a20fec01166d8cf6571d0e165ad11cfe5a8134a2a48a36d42ab291c59c6deca5264cbb
languageName: node
linkType: hard
@@ -10218,27 +10188,27 @@ __metadata:
linkType: hard
"rollup@npm:^4.20.0, rollup@npm:^4.24.0":
- version: 4.26.0
- resolution: "rollup@npm:4.26.0"
- dependencies:
- "@rollup/rollup-android-arm-eabi": "npm:4.26.0"
- "@rollup/rollup-android-arm64": "npm:4.26.0"
- "@rollup/rollup-darwin-arm64": "npm:4.26.0"
- "@rollup/rollup-darwin-x64": "npm:4.26.0"
- "@rollup/rollup-freebsd-arm64": "npm:4.26.0"
- "@rollup/rollup-freebsd-x64": "npm:4.26.0"
- "@rollup/rollup-linux-arm-gnueabihf": "npm:4.26.0"
- "@rollup/rollup-linux-arm-musleabihf": "npm:4.26.0"
- "@rollup/rollup-linux-arm64-gnu": "npm:4.26.0"
- "@rollup/rollup-linux-arm64-musl": "npm:4.26.0"
- "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.26.0"
- "@rollup/rollup-linux-riscv64-gnu": "npm:4.26.0"
- "@rollup/rollup-linux-s390x-gnu": "npm:4.26.0"
- "@rollup/rollup-linux-x64-gnu": "npm:4.26.0"
- "@rollup/rollup-linux-x64-musl": "npm:4.26.0"
- "@rollup/rollup-win32-arm64-msvc": "npm:4.26.0"
- "@rollup/rollup-win32-ia32-msvc": "npm:4.26.0"
- "@rollup/rollup-win32-x64-msvc": "npm:4.26.0"
+ version: 4.27.3
+ resolution: "rollup@npm:4.27.3"
+ dependencies:
+ "@rollup/rollup-android-arm-eabi": "npm:4.27.3"
+ "@rollup/rollup-android-arm64": "npm:4.27.3"
+ "@rollup/rollup-darwin-arm64": "npm:4.27.3"
+ "@rollup/rollup-darwin-x64": "npm:4.27.3"
+ "@rollup/rollup-freebsd-arm64": "npm:4.27.3"
+ "@rollup/rollup-freebsd-x64": "npm:4.27.3"
+ "@rollup/rollup-linux-arm-gnueabihf": "npm:4.27.3"
+ "@rollup/rollup-linux-arm-musleabihf": "npm:4.27.3"
+ "@rollup/rollup-linux-arm64-gnu": "npm:4.27.3"
+ "@rollup/rollup-linux-arm64-musl": "npm:4.27.3"
+ "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.27.3"
+ "@rollup/rollup-linux-riscv64-gnu": "npm:4.27.3"
+ "@rollup/rollup-linux-s390x-gnu": "npm:4.27.3"
+ "@rollup/rollup-linux-x64-gnu": "npm:4.27.3"
+ "@rollup/rollup-linux-x64-musl": "npm:4.27.3"
+ "@rollup/rollup-win32-arm64-msvc": "npm:4.27.3"
+ "@rollup/rollup-win32-ia32-msvc": "npm:4.27.3"
+ "@rollup/rollup-win32-x64-msvc": "npm:4.27.3"
"@types/estree": "npm:1.0.6"
fsevents: "npm:~2.3.2"
dependenciesMeta:
@@ -10282,7 +10252,7 @@ __metadata:
optional: true
bin:
rollup: dist/bin/rollup
- checksum: 10c0/a4375787b95bc3b55d38bbb8dec5f6a63862b08369b9562a2d38efadd400ca42a79406b8f09670a0deb0cc9cd72cca1c0be317302190d1f7feff597003d951bc
+ checksum: 10c0/789885d3f852ed7ca45bed14194a2ac7a2cf16b6b62b54f691c79e27d5557d31a2d612d3680c26c527a1957e0bd6811806ddd765e0dae589404cf24544ff2838
languageName: node
linkType: hard
@@ -10615,12 +10585,12 @@ __metadata:
languageName: node
linkType: hard
-"smoldot@npm:2.0.31":
- version: 2.0.31
- resolution: "smoldot@npm:2.0.31"
+"smoldot@npm:2.0.33":
+ version: 2.0.33
+ resolution: "smoldot@npm:2.0.33"
dependencies:
ws: "npm:^8.8.1"
- checksum: 10c0/610bf1ae1a80e7f682af144e2d0088e4d49949089c7b8bc29961ec112e120af78b7bf181718ad5f923cfca69d6b5ce23894ab10872dac6595ca1554277606977
+ checksum: 10c0/dada517972924017077b4e8c6f76169ddcd371c270e714db42e034c0c974898a15f640759576b712f9d0aa3e2f1bb01c7e5d2e711e329f0f6837902ac51bb1fa
languageName: node
linkType: hard
@@ -11360,7 +11330,7 @@ __metadata:
languageName: node
linkType: hard
-"tsup@npm:^8.2.4":
+"tsup@npm:^8.3.5":
version: 8.3.5
resolution: "tsup@npm:8.3.5"
dependencies:
@@ -11432,9 +11402,9 @@ __metadata:
linkType: hard
"type-fest@npm:^4.23.0, type-fest@npm:^4.6.0, type-fest@npm:^4.7.1":
- version: 4.26.1
- resolution: "type-fest@npm:4.26.1"
- checksum: 10c0/d2719ff8d380befe8a3c61068f37f28d6fa2849fd140c5d2f0f143099e371da6856aad7c97e56b83329d45bfe504afe9fd936a7cff600cc0d46aa9ffb008d6c6
+ version: 4.27.0
+ resolution: "type-fest@npm:4.27.0"
+ checksum: 10c0/30c8ebe1219725021f5b5006081bd828c4e915de0de65e9a87065f566a96ece706846b2c874ac04c0dcfdfe6b4ae47ad15d3285c9aab162cb79c026dfb2e7556
languageName: node
linkType: hard
@@ -11490,7 +11460,7 @@ __metadata:
languageName: node
linkType: hard
-"typescript@npm:^5.4.3, typescript@npm:^5.5.4":
+"typescript@npm:^5.4.3, typescript@npm:^5.6.3":
version: 5.6.3
resolution: "typescript@npm:5.6.3"
bin:
@@ -11500,7 +11470,7 @@ __metadata:
languageName: node
linkType: hard
-"typescript@patch:typescript@npm%3A^5.4.3#optional!builtin, typescript@patch:typescript@npm%3A^5.5.4#optional!builtin":
+"typescript@patch:typescript@npm%3A^5.4.3#optional!builtin, typescript@patch:typescript@npm%3A^5.6.3#optional!builtin":
version: 5.6.3
resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=5adc0c"
bin:
@@ -11839,8 +11809,8 @@ __metadata:
linkType: hard
"viem@npm:^2.1.1, viem@npm:^2.21.35":
- version: 2.21.45
- resolution: "viem@npm:2.21.45"
+ version: 2.21.48
+ resolution: "viem@npm:2.21.48"
dependencies:
"@noble/curves": "npm:1.6.0"
"@noble/hashes": "npm:1.5.0"
@@ -11856,7 +11826,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 10c0/3ed93c58dc125c97f35970b17d3dca6dfe6a8811d45fed84dc5bdd4a57860c880ae5a41a45cb8caa500925450b52d3a225d8def8422e7dd7ecead3bcc3921ec8
+ checksum: 10c0/e9b2799535263a859bddda25d962b13d2c76aec191e1849dd0f268c32a43eb65932a05cc5be270c92e19d79aafda73884690c0b0fbdb9311266a01ea3f659082
languageName: node
linkType: hard
@@ -11969,8 +11939,8 @@ __metadata:
linkType: hard
"vite-tsconfig-paths@npm:^5.0.1":
- version: 5.1.2
- resolution: "vite-tsconfig-paths@npm:5.1.2"
+ version: 5.1.3
+ resolution: "vite-tsconfig-paths@npm:5.1.3"
dependencies:
debug: "npm:^4.1.1"
globrex: "npm:^0.1.2"
@@ -11980,7 +11950,7 @@ __metadata:
peerDependenciesMeta:
vite:
optional: true
- checksum: 10c0/7db445b6b1f48e7b89f39f5eb8cf4ea645994f581fcc7c9fac721e0c36f8203c0770007ec27825caa6e2566e3127b2b1bfe8be28ca05cd0e9fb67a2943dcdec5
+ checksum: 10c0/fb7480efa31fd50439f4a12c91bc953e5cc09d69fdc7eeb6ffff7cc796bc2c1f2c617c3abfdcbf5d7414848076cea9deb60bc002142f93b6e3131e5458760710
languageName: node
linkType: hard
@@ -12145,11 +12115,11 @@ __metadata:
linkType: hard
"wagmi@npm:^2.12.25":
- version: 2.12.32
- resolution: "wagmi@npm:2.12.32"
+ version: 2.13.0
+ resolution: "wagmi@npm:2.13.0"
dependencies:
- "@wagmi/connectors": "npm:5.3.10"
- "@wagmi/core": "npm:2.14.6"
+ "@wagmi/connectors": "npm:5.5.0"
+ "@wagmi/core": "npm:2.15.0"
use-sync-external-store: "npm:1.2.0"
peerDependencies:
"@tanstack/react-query": ">=5.0.0"
@@ -12159,7 +12129,7 @@ __metadata:
peerDependenciesMeta:
typescript:
optional: true
- checksum: 10c0/eea7ac5ffedd83d65529591a0a80873b2bf04f93906a8f29fea7704970a8c7dd732871a13f2dfcaa5e34462c2d25038596eb782142d9493bc396e18d3adf6b01
+ checksum: 10c0/fb3946009dca3e244c538ac72691bc263f95f1f6eef12f6720164b515adb8d3a9af063df773307f2206fa649d5821e4bb3d152bef734b4552a5360cf9237db80
languageName: node
linkType: hard
@@ -12487,9 +12457,9 @@ __metadata:
linkType: hard
"xxhash-wasm@npm:^1.0.2":
- version: 1.0.2
- resolution: "xxhash-wasm@npm:1.0.2"
- checksum: 10c0/5ba899d9216d9897de2d61a5331b16c99226e75ce47895fc8c730bac5cb00e6e50856dd8f489c12b3012f0fc81b6894806b2e44d2eb3cc7843919793485a30d1
+ version: 1.1.0
+ resolution: "xxhash-wasm@npm:1.1.0"
+ checksum: 10c0/35aa152fc7d775ae13364fe4fb20ebd89c6ac1f56cdb6060a6d2f1ed68d15180694467e63a4adb3d11936a4798ccd75a540979070e70d9b911e9981bbdd9cea6
languageName: node
linkType: hard
From 0537bd55d43c0e3bd7ced4132308824aa8fe72b5 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 13:46:44 +0700
Subject: [PATCH 65/84] Ledger signer working
---
.../contexts/LedgerHardware/static/ledger.ts | 18 +++--
.../src/hooks/useSubmitExtrinsic/index.tsx | 29 ++++++-
.../app/src/library/Signers/LedgerSigner.ts | 79 +++++++++++++++++++
.../SubmitTx/ManualSign/Ledger/Submit.tsx | 37 +--------
4 files changed, 117 insertions(+), 46 deletions(-)
create mode 100644 packages/app/src/library/Signers/LedgerSigner.ts
diff --git a/packages/app/src/contexts/LedgerHardware/static/ledger.ts b/packages/app/src/contexts/LedgerHardware/static/ledger.ts
index b9b18536c..3d7eca161 100644
--- a/packages/app/src/contexts/LedgerHardware/static/ledger.ts
+++ b/packages/app/src/contexts/LedgerHardware/static/ledger.ts
@@ -70,19 +70,21 @@ export class Ledger {
static signPayload = async (
app: PolkadotGenericApp,
index: number,
- payload: AnyJson,
- txMetadata: AnyJson
+ payload: Uint8Array,
+ txMetadata?: Uint8Array
) => {
await this.ensureOpen();
const bip42Path = `m/44'/354'/${index}'/${0}'/${0}'`;
- const buff = Buffer.from(txMetadata);
+ const toSign = Buffer.from(payload);
- const result = await app.signWithMetadata(
- bip42Path,
- payload.toU8a(true),
- buff
- );
+ let result;
+ if (txMetadata) {
+ const buff = Buffer.from(txMetadata);
+ result = await app.signWithMetadata(bip42Path, toSign, buff);
+ } else {
+ result = app.sign(bip42Path, toSign);
+ }
await this.ensureClosed();
return result;
diff --git a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
index b413b04ad..279e69bbb 100644
--- a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
+++ b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
@@ -20,9 +20,13 @@ import { useProxySupported } from 'hooks/useProxySupported';
import { ApiController } from 'controllers/Api';
import { useNetwork } from 'contexts/Network';
import { useBalances } from 'contexts/Balances';
-import { InvalidTxError } from 'polkadot-api';
+import type { PolkadotSigner } from 'polkadot-api';
+import { AccountId, InvalidTxError } from 'polkadot-api';
import { connectInjectedExtension } from 'polkadot-api/pjs-signer';
import { formatAccountSs58 } from '@w3ux/utils';
+import { LedgerSigner } from 'library/Signers/LedgerSigner';
+import { getLedgerApp } from 'contexts/LedgerHardware/Utils';
+import type { LedgerAccount } from '@w3ux/react-connect-kit/types';
export const useSubmitExtrinsic = ({
tx,
@@ -32,7 +36,10 @@ export const useSubmitExtrinsic = ({
callbackInBlock,
}: UseSubmitExtrinsicProps): UseSubmitExtrinsic => {
const { t } = useTranslation('library');
- const { network } = useNetwork();
+ const {
+ network,
+ networkData: { units, unit },
+ } = useNetwork();
const { getNonce } = useBalances();
const { activeProxy } = useActiveAccounts();
const { extensionsStatus } = useExtensions();
@@ -218,9 +225,23 @@ export const useSubmitExtrinsic = ({
setSubmitting(true);
// handle signed transaction.
- let signer;
+ let signer: PolkadotSigner | undefined;
if (requiresManualSign(fromRef.current)) {
- // TODO: Get custom signer here.
+ if (source === 'ledger') {
+ // Ledger signer.
+ signer = await new LedgerSigner(
+ AccountId().enc(fromRef.current),
+ getLedgerApp(network).txMetadataChainId
+ ).getPolkadotSigner(
+ {
+ decimals: units,
+ tokenSymbol: unit,
+ },
+ (account as LedgerAccount).index
+ );
+ }
+
+ // TODO: Get Vault & Wallet Connect signers.
} else {
// Get the polkadot signer for this account.
signer = (await connectInjectedExtension(source))
diff --git a/packages/app/src/library/Signers/LedgerSigner.ts b/packages/app/src/library/Signers/LedgerSigner.ts
new file mode 100644
index 000000000..a1eca9c67
--- /dev/null
+++ b/packages/app/src/library/Signers/LedgerSigner.ts
@@ -0,0 +1,79 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import { merkleizeMetadata } from '@polkadot-api/merkleize-metadata';
+import type { PolkadotSigner } from 'polkadot-api';
+import { mergeUint8 } from 'polkadot-api/utils';
+import type { V15 } from '@polkadot-api/substrate-bindings';
+import { decAnyMetadata } from '@polkadot-api/substrate-bindings';
+import { Ledger } from '../../contexts/LedgerHardware/static/ledger';
+import { createV4Tx, getSignBytes } from '@polkadot-api/signers-common';
+
+const CheckMetadataHash = 'CheckMetadataHash';
+
+export class LedgerSigner {
+ #publicKey: Uint8Array;
+ #txMetadataChainId: string;
+
+ constructor(pubKey: Uint8Array, txMetadataChainId: string) {
+ this.#publicKey = pubKey;
+ this.#txMetadataChainId = txMetadataChainId;
+ }
+
+ async getPolkadotSigner(
+ networkInfo: { decimals: number; tokenSymbol: string },
+ index: number
+ ): Promise {
+ const { app } = await Ledger.initialise(this.#txMetadataChainId);
+
+ const signTx: PolkadotSigner['signTx'] = async (
+ callData,
+ signedExtensions,
+ metadata
+ ) => {
+ const merkleizer = merkleizeMetadata(metadata, networkInfo);
+ const digest = merkleizer.digest();
+
+ // NOTE: Assuming metadata is version 15. Could introduce error here for `useSubmitExtrinsic`
+ // to handle.
+ const v15 = decAnyMetadata(metadata).metadata.value as unknown as V15;
+
+ // NOTE: Assuming `CheckMetadataHash` signed extension exists in metadata. Could introduce
+ // error here for `useSubmitExtrinsic` to handle.
+ const extra: Uint8Array[] = [];
+ const additionalSigned: Uint8Array[] = [];
+ v15.extrinsic.signedExtensions.map(({ identifier }) => {
+ if (identifier === CheckMetadataHash) {
+ extra.push(Uint8Array.from([1]));
+ additionalSigned.push(mergeUint8(Uint8Array.from([1]), digest));
+ return;
+ }
+ const signedExtension = signedExtensions[identifier];
+ if (signedExtension) {
+ extra.push(signedExtension.value);
+ additionalSigned.push(signedExtension.additionalSigned);
+ }
+ });
+
+ const toSign = mergeUint8(callData, ...extra, ...additionalSigned);
+ const { signature } = await Ledger.signPayload(
+ app,
+ index,
+ toSign,
+ merkleizer.getProofForExtrinsicPayload(toSign)
+ );
+ return createV4Tx(v15, this.#publicKey, signature, extra, callData);
+ };
+
+ return {
+ publicKey: this.#publicKey,
+ signTx,
+ signBytes: getSignBytes(async (x) => {
+ const { signature } = await Ledger.signPayload(app, index, x);
+ // NOTE: the signature includes a "0x00" at the beginning, indicating a ed25519 signature.
+ // this is not needed for non-extrinsic signatures.
+ return signature.subarray(1);
+ }),
+ };
+ }
+}
diff --git a/packages/app/src/library/SubmitTx/ManualSign/Ledger/Submit.tsx b/packages/app/src/library/SubmitTx/ManualSign/Ledger/Submit.tsx
index e6e2aeab9..a76e7e330 100644
--- a/packages/app/src/library/SubmitTx/ManualSign/Ledger/Submit.tsx
+++ b/packages/app/src/library/SubmitTx/ManualSign/Ledger/Submit.tsx
@@ -3,9 +3,6 @@
import { faUsb } from '@fortawesome/free-brands-svg-icons';
import { faSquarePen } from '@fortawesome/free-solid-svg-icons';
-import type { LedgerAccount } from '@w3ux/react-connect-kit/types';
-import { useActiveAccounts } from 'contexts/ActiveAccounts';
-import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
import { useLedgerHardware } from 'contexts/LedgerHardware';
import { getLedgerApp } from 'contexts/LedgerHardware/Utils';
import { useNetwork } from 'contexts/Network';
@@ -23,37 +20,11 @@ export const Submit = ({
disabled,
}: LedgerSubmitProps) => {
const { t } = useTranslation('library');
- const {
- handleSignTx,
- getIsExecuting,
- integrityChecked,
- checkRuntimeVersion,
- } = useLedgerHardware();
const { network } = useNetwork();
const { getTxSignature } = useTxMeta();
- const { getAccount } = useImportedAccounts();
- const { activeAccount } = useActiveAccounts();
- const { getTxMetadata, getTxPayload, getPayloadUid } = useTxMeta();
const { txMetadataChainId } = getLedgerApp(network);
-
- const getAddressIndex = () =>
- (getAccount(activeAccount) as LedgerAccount)?.index || 0;
-
- // Handle transaction submission
- const handleTxSubmit = async () => {
- const uid = getPayloadUid();
- const accountIndex = getAddressIndex();
- const txMetadata = await getTxMetadata();
- const payload = await getTxPayload();
-
- await handleSignTx(
- txMetadataChainId,
- uid,
- accountIndex,
- payload,
- txMetadata
- );
- };
+ const { getIsExecuting, integrityChecked, checkRuntimeVersion } =
+ useLedgerHardware();
// Check device runtime version.
const handleCheckRuntimeVersion = async () => {
@@ -66,9 +37,7 @@ export const Submit = ({
// Button `onClick` handler depends whether integrityChecked and whether tx has been submitted.
const handleOnClick = !integrityChecked
? handleCheckRuntimeVersion
- : txReady
- ? onSubmit
- : handleTxSubmit;
+ : onSubmit;
// Determine button text.
const text = !integrityChecked
From d604440ffb3acdbccf38835843628127d93c3e0c Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 13:59:59 +0700
Subject: [PATCH 66/84] queries, apis at best
---
.../src/canvas/JoinPool/Overview/Stats.tsx | 3 +-
.../src/contexts/Pools/ActivePool/index.tsx | 6 ++-
.../src/model/Entries/BondedPools/index.tsx | 10 ++--
.../app/src/model/Entries/Validators/index.ts | 2 +-
.../app/src/model/ErasStakersPaged/index.tsx | 3 +-
.../app/src/model/Query/BondedMulti/index.ts | 5 +-
.../src/model/Query/ClaimedRewards/index.ts | 5 +-
packages/app/src/model/Query/Era/index.ts | 4 +-
.../src/model/Query/ErasRewardPoints/index.ts | 5 +-
.../Query/ErasRewardPointsMulti/index.ts | 5 +-
.../model/Query/ErasStakersOverview/index.tsx | 4 +-
.../model/Query/ErasValidatorReward/index.ts | 4 +-
.../Query/ErasValidatorRewardMulti/index.ts | 5 +-
.../src/model/Query/IdentityOfMulti/index.ts | 5 +-
.../app/src/model/Query/NetworkMeta/index.ts | 52 +++++++++++--------
.../src/model/Query/NominatorsMulti/index.ts | 3 +-
.../model/Query/ParaSessionAccounts/index.ts | 3 +-
.../model/Query/PoolMetadataMulti/index.ts | 3 +-
.../app/src/model/Query/ProxiesQuery/index.ts | 3 +-
.../model/Query/SessionValidators/index.ts | 4 +-
.../app/src/model/Query/SuperOfMulti/index.ts | 3 +-
.../src/model/Query/ValidatorPrefs/index.ts | 3 +-
.../src/model/Query/ValidatorsMulti/index.ts | 3 +-
.../model/Subscribe/AccountBalances/index.ts | 3 +-
24 files changed, 97 insertions(+), 49 deletions(-)
diff --git a/packages/app/src/canvas/JoinPool/Overview/Stats.tsx b/packages/app/src/canvas/JoinPool/Overview/Stats.tsx
index 4722836a0..7e461d8f1 100644
--- a/packages/app/src/canvas/JoinPool/Overview/Stats.tsx
+++ b/packages/app/src/canvas/JoinPool/Overview/Stats.tsx
@@ -50,7 +50,8 @@ export const Stats = ({
const apiResult = await pApi.apis.NominationPoolsApi.points_to_balance(
bondedPool.id,
- BigInt(rmCommas(bondedPool.points))
+ BigInt(rmCommas(bondedPool.points)),
+ { at: 'best' }
);
const balance = new BigNumber(apiResult?.toString() || 0);
diff --git a/packages/app/src/contexts/Pools/ActivePool/index.tsx b/packages/app/src/contexts/Pools/ActivePool/index.tsx
index f5209bba7..f8e535233 100644
--- a/packages/app/src/contexts/Pools/ActivePool/index.tsx
+++ b/packages/app/src/contexts/Pools/ActivePool/index.tsx
@@ -195,8 +195,10 @@ export const ActivePoolProvider = ({ children }: { children: ReactNode }) => {
const fetchPendingRewards = async (address: string | undefined) => {
const { pApi } = ApiController.get(network);
if (pApi && address) {
- const apiResult =
- await pApi.apis.NominationPoolsApi.pending_rewards(address);
+ const apiResult = await pApi.apis.NominationPoolsApi.pending_rewards(
+ address,
+ { at: 'best' }
+ );
return new BigNumber(apiResult?.toString() || 0);
}
return new BigNumber(0);
diff --git a/packages/app/src/model/Entries/BondedPools/index.tsx b/packages/app/src/model/Entries/BondedPools/index.tsx
index 9fa767917..4f34b5600 100644
--- a/packages/app/src/model/Entries/BondedPools/index.tsx
+++ b/packages/app/src/model/Entries/BondedPools/index.tsx
@@ -17,13 +17,17 @@ export class BondedPools {
async fetch() {
this.bondedPools =
- await this.#pApi.query.NominationPools.BondedPools.getEntries();
+ await this.#pApi.query.NominationPools.BondedPools.getEntries({
+ at: 'best',
+ });
return this;
}
async fetchOne(id: number) {
- const result =
- await this.#pApi.query.NominationPools.BondedPools.getValue(id);
+ const result = await this.#pApi.query.NominationPools.BondedPools.getValue(
+ id,
+ { at: 'best' }
+ );
if (!result) {
return null;
diff --git a/packages/app/src/model/Entries/Validators/index.ts b/packages/app/src/model/Entries/Validators/index.ts
index 1f64955f5..b5eea430d 100644
--- a/packages/app/src/model/Entries/Validators/index.ts
+++ b/packages/app/src/model/Entries/Validators/index.ts
@@ -11,6 +11,6 @@ export class Validators {
}
async fetch() {
- return await this.#pApi.query.Staking.Validators.getEntries();
+ return await this.#pApi.query.Staking.Validators.getEntries({ at: 'best' });
}
}
diff --git a/packages/app/src/model/ErasStakersPaged/index.tsx b/packages/app/src/model/ErasStakersPaged/index.tsx
index a7a3a57f3..144800800 100644
--- a/packages/app/src/model/ErasStakersPaged/index.tsx
+++ b/packages/app/src/model/ErasStakersPaged/index.tsx
@@ -13,7 +13,8 @@ export class ErasStakersPaged {
async fetch(era: string, validator: string) {
return await this.#pApi.query.Staking.ErasStakersPaged.getEntries(
era,
- validator
+ validator,
+ { at: 'best' }
);
}
}
diff --git a/packages/app/src/model/Query/BondedMulti/index.ts b/packages/app/src/model/Query/BondedMulti/index.ts
index d56d994d9..80fb032ad 100644
--- a/packages/app/src/model/Query/BondedMulti/index.ts
+++ b/packages/app/src/model/Query/BondedMulti/index.ts
@@ -16,7 +16,10 @@ export class BondedMulti {
async fetch() {
try {
const results = await this.#pApi.query.Staking.Bonded.getValues(
- this.#addresses
+ this.#addresses,
+ {
+ at: 'best',
+ }
);
return results;
} catch (e) {
diff --git a/packages/app/src/model/Query/ClaimedRewards/index.ts b/packages/app/src/model/Query/ClaimedRewards/index.ts
index 35a90cfdf..6fabb0332 100644
--- a/packages/app/src/model/Query/ClaimedRewards/index.ts
+++ b/packages/app/src/model/Query/ClaimedRewards/index.ts
@@ -20,7 +20,10 @@ export class ClaimedRewards {
try {
const result = await this.#pApi.query.Staking.ClaimedRewards.getValue(
this.#era,
- this.#address
+ this.#address,
+ {
+ at: 'best',
+ }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Query/Era/index.ts b/packages/app/src/model/Query/Era/index.ts
index d572c27f5..5100ced58 100644
--- a/packages/app/src/model/Query/Era/index.ts
+++ b/packages/app/src/model/Query/Era/index.ts
@@ -15,7 +15,9 @@ export class Era {
let result;
try {
const { index, start } =
- await this.#pApi.query.Staking.ActiveEra.getValue();
+ await this.#pApi.query.Staking.ActiveEra.getValue({
+ at: 'best',
+ });
result = {
start,
diff --git a/packages/app/src/model/Query/ErasRewardPoints/index.ts b/packages/app/src/model/Query/ErasRewardPoints/index.ts
index 149910abb..6ac3b3075 100644
--- a/packages/app/src/model/Query/ErasRewardPoints/index.ts
+++ b/packages/app/src/model/Query/ErasRewardPoints/index.ts
@@ -16,7 +16,10 @@ export class ErasRewardPoints {
async fetch() {
try {
const result = await this.#pApi.query.Staking.ErasRewardPoints.getValue(
- this.#era
+ this.#era,
+ {
+ at: 'best',
+ }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Query/ErasRewardPointsMulti/index.ts b/packages/app/src/model/Query/ErasRewardPointsMulti/index.ts
index 14ac6a518..2c02adcc1 100644
--- a/packages/app/src/model/Query/ErasRewardPointsMulti/index.ts
+++ b/packages/app/src/model/Query/ErasRewardPointsMulti/index.ts
@@ -16,7 +16,10 @@ export class ErasRewardPointsMulti {
async fetch() {
try {
const results = await this.#pApi.query.Staking.ErasRewardPoints.getValues(
- this.#eras
+ this.#eras,
+ {
+ at: 'best',
+ }
);
return results;
} catch (e) {
diff --git a/packages/app/src/model/Query/ErasStakersOverview/index.tsx b/packages/app/src/model/Query/ErasStakersOverview/index.tsx
index 8c42b5d3a..cae72128e 100644
--- a/packages/app/src/model/Query/ErasStakersOverview/index.tsx
+++ b/packages/app/src/model/Query/ErasStakersOverview/index.tsx
@@ -11,6 +11,8 @@ export class ErasStakersOverview {
}
async fetch(era: string) {
- return await this.#pApi.query.Staking.ErasStakersOverview.getEntries(era);
+ return await this.#pApi.query.Staking.ErasStakersOverview.getEntries(era, {
+ at: 'best',
+ });
}
}
diff --git a/packages/app/src/model/Query/ErasValidatorReward/index.ts b/packages/app/src/model/Query/ErasValidatorReward/index.ts
index fc6a9b9bf..bcdc54daf 100644
--- a/packages/app/src/model/Query/ErasValidatorReward/index.ts
+++ b/packages/app/src/model/Query/ErasValidatorReward/index.ts
@@ -16,7 +16,9 @@ export class ErasValidatorReward {
async fetch() {
try {
const result =
- await this.#pApi.query.Staking.ErasValidatorReward.getValue(this.#era);
+ await this.#pApi.query.Staking.ErasValidatorReward.getValue(this.#era, {
+ at: 'best',
+ });
return result;
} catch (e) {
// Silently fail.
diff --git a/packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts b/packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts
index 61894f746..f57bc15e0 100644
--- a/packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts
+++ b/packages/app/src/model/Query/ErasValidatorRewardMulti/index.ts
@@ -17,7 +17,10 @@ export class ErasValidatorReward {
try {
const results =
await this.#pApi.query.Staking.ErasValidatorReward.getValues(
- this.#eras
+ this.#eras,
+ {
+ at: 'best',
+ }
);
return results;
} catch (e) {
diff --git a/packages/app/src/model/Query/IdentityOfMulti/index.ts b/packages/app/src/model/Query/IdentityOfMulti/index.ts
index 19ea4332e..f96df081d 100644
--- a/packages/app/src/model/Query/IdentityOfMulti/index.ts
+++ b/packages/app/src/model/Query/IdentityOfMulti/index.ts
@@ -16,7 +16,10 @@ export class IdentityOfMulti {
async fetch() {
try {
const result = await this.#pApi.query.Identity.IdentityOf.getValues(
- this.#addresses
+ this.#addresses,
+ {
+ at: 'best',
+ }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Query/NetworkMeta/index.ts b/packages/app/src/model/Query/NetworkMeta/index.ts
index f8e99dc2b..80b48eabe 100644
--- a/packages/app/src/model/Query/NetworkMeta/index.ts
+++ b/packages/app/src/model/Query/NetworkMeta/index.ts
@@ -15,8 +15,9 @@ export class NetworkMeta {
// Fetch network constants.
async fetch(activeEra: APIActiveEra, previousEra: BigNumber) {
+ const at = { at: 'best' };
const totalIssuance =
- await this.#pApi.query.Balances.TotalIssuance.getValue();
+ await this.#pApi.query.Balances.TotalIssuance.getValue(at);
const [
auctionCounter,
@@ -42,31 +43,36 @@ export class NetworkMeta {
minNominatorBond,
activeEraErasTotalStake,
] = await Promise.all([
- this.#pApi.query.Auctions.AuctionCounter.getValue(),
- this.#pApi.query.ParaSessionInfo.EarliestStoredSession.getValue(),
- this.#pApi.query.FastUnstake.ErasToCheckPerBlock.getValue(),
- this.#pApi.query.Staking.MinimumActiveStake.getValue(),
- this.#pApi.query.NominationPools.CounterForPoolMembers.getValue(),
- this.#pApi.query.NominationPools.CounterForBondedPools.getValue(),
- this.#pApi.query.NominationPools.CounterForRewardPools.getValue(),
- this.#pApi.query.NominationPools.LastPoolId.getValue(),
- this.#pApi.query.NominationPools.MaxPoolMembers.getValue(),
- this.#pApi.query.NominationPools.MaxPoolMembersPerPool.getValue(),
- this.#pApi.query.NominationPools.MaxPools.getValue(),
- this.#pApi.query.NominationPools.MinCreateBond.getValue(),
- this.#pApi.query.NominationPools.MinJoinBond.getValue(),
- this.#pApi.query.NominationPools.GlobalMaxCommission.getValue(),
- this.#pApi.query.Staking.CounterForNominators.getValue(),
- this.#pApi.query.Staking.CounterForValidators.getValue(),
- this.#pApi.query.Staking.MaxValidatorsCount.getValue(),
- this.#pApi.query.Staking.ValidatorCount.getValue(),
+ this.#pApi.query.Auctions.AuctionCounter.getValue(at),
+ this.#pApi.query.ParaSessionInfo.EarliestStoredSession.getValue(at),
+ this.#pApi.query.FastUnstake.ErasToCheckPerBlock.getValue(at),
+ this.#pApi.query.Staking.MinimumActiveStake.getValue(at),
+ this.#pApi.query.NominationPools.CounterForPoolMembers.getValue(at),
+ this.#pApi.query.NominationPools.CounterForBondedPools.getValue(at),
+ this.#pApi.query.NominationPools.CounterForRewardPools.getValue(at),
+ this.#pApi.query.NominationPools.LastPoolId.getValue(at),
+ this.#pApi.query.NominationPools.MaxPoolMembers.getValue(at),
+ this.#pApi.query.NominationPools.MaxPoolMembersPerPool.getValue(at),
+ this.#pApi.query.NominationPools.MaxPools.getValue(at),
+ this.#pApi.query.NominationPools.MinCreateBond.getValue(at),
+ this.#pApi.query.NominationPools.MinJoinBond.getValue(at),
+ this.#pApi.query.NominationPools.GlobalMaxCommission.getValue(at),
+ this.#pApi.query.Staking.CounterForNominators.getValue(at),
+ this.#pApi.query.Staking.CounterForValidators.getValue(at),
+ this.#pApi.query.Staking.MaxValidatorsCount.getValue(at),
+ this.#pApi.query.Staking.ValidatorCount.getValue(at),
this.#pApi.query.Staking.ErasValidatorReward.getValue(
- previousEra.toString()
+ previousEra.toString(),
+ at
),
- this.#pApi.query.Staking.ErasTotalStake.getValue(previousEra.toString()),
- this.#pApi.query.Staking.MinNominatorBond.getValue(),
this.#pApi.query.Staking.ErasTotalStake.getValue(
- activeEra.index.toString()
+ previousEra.toString(),
+ at
+ ),
+ this.#pApi.query.Staking.MinNominatorBond.getValue(at),
+ this.#pApi.query.Staking.ErasTotalStake.getValue(
+ activeEra.index.toString(),
+ at
),
]);
diff --git a/packages/app/src/model/Query/NominatorsMulti/index.ts b/packages/app/src/model/Query/NominatorsMulti/index.ts
index c9279c596..7f93d4e79 100644
--- a/packages/app/src/model/Query/NominatorsMulti/index.ts
+++ b/packages/app/src/model/Query/NominatorsMulti/index.ts
@@ -17,7 +17,8 @@ export class NominatorsMulti {
let result;
try {
result = await this.#pApi.query.Staking.Nominators.getValues(
- this.#addresses
+ this.#addresses,
+ { at: 'best' }
);
return result.map((nominator) => {
diff --git a/packages/app/src/model/Query/ParaSessionAccounts/index.ts b/packages/app/src/model/Query/ParaSessionAccounts/index.ts
index 76ff767f7..1aedab661 100644
--- a/packages/app/src/model/Query/ParaSessionAccounts/index.ts
+++ b/packages/app/src/model/Query/ParaSessionAccounts/index.ts
@@ -17,7 +17,8 @@ export class ParaSessionAccounts {
try {
const result =
await this.#pApi.query.ParaSessionInfo.AccountKeys.getValue(
- this.#session
+ this.#session,
+ { at: 'best' }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Query/PoolMetadataMulti/index.ts b/packages/app/src/model/Query/PoolMetadataMulti/index.ts
index e28220f5b..59f9c836f 100644
--- a/packages/app/src/model/Query/PoolMetadataMulti/index.ts
+++ b/packages/app/src/model/Query/PoolMetadataMulti/index.ts
@@ -16,7 +16,8 @@ export class PoolMetadataMulti {
async fetch() {
try {
const result = await this.#pApi.query.NominationPools.Metadata.getValues(
- this.#ids
+ this.#ids,
+ { at: 'best' }
);
return result.map((metadata) => metadata.asText());
} catch (e) {
diff --git a/packages/app/src/model/Query/ProxiesQuery/index.ts b/packages/app/src/model/Query/ProxiesQuery/index.ts
index 49866d57b..2237c02d5 100644
--- a/packages/app/src/model/Query/ProxiesQuery/index.ts
+++ b/packages/app/src/model/Query/ProxiesQuery/index.ts
@@ -16,7 +16,8 @@ export class ProxiesQuery {
async fetch() {
try {
const result = await this.#pApi.query.Proxy.Proxies.getValue(
- this.#address
+ this.#address,
+ { at: 'best' }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Query/SessionValidators/index.ts b/packages/app/src/model/Query/SessionValidators/index.ts
index 6b35d998c..011d08f87 100644
--- a/packages/app/src/model/Query/SessionValidators/index.ts
+++ b/packages/app/src/model/Query/SessionValidators/index.ts
@@ -13,7 +13,9 @@ export class SessionValidators {
// Fetch network constants.
async fetch() {
try {
- const result = await this.#pApi.query.Session.Validators.getValue();
+ const result = await this.#pApi.query.Session.Validators.getValue({
+ at: 'best',
+ });
return result;
} catch (e) {
// Silently fail.
diff --git a/packages/app/src/model/Query/SuperOfMulti/index.ts b/packages/app/src/model/Query/SuperOfMulti/index.ts
index 3ae9eb11c..6f1c1d8f8 100644
--- a/packages/app/src/model/Query/SuperOfMulti/index.ts
+++ b/packages/app/src/model/Query/SuperOfMulti/index.ts
@@ -16,7 +16,8 @@ export class SuperOfMulti {
async fetch() {
try {
const result = await this.#pApi.query.Identity.SuperOf.getValues(
- this.#addresses
+ this.#addresses,
+ { at: 'best' }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Query/ValidatorPrefs/index.ts b/packages/app/src/model/Query/ValidatorPrefs/index.ts
index 9554a8246..086a61949 100644
--- a/packages/app/src/model/Query/ValidatorPrefs/index.ts
+++ b/packages/app/src/model/Query/ValidatorPrefs/index.ts
@@ -20,7 +20,8 @@ export class ValidatorPrefs {
try {
const result = await this.#pApi.query.Staking.ErasValidatorPrefs.getValue(
this.#era,
- this.#address
+ this.#address,
+ { at: 'best' }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Query/ValidatorsMulti/index.ts b/packages/app/src/model/Query/ValidatorsMulti/index.ts
index 66c17bc8d..414037ecc 100644
--- a/packages/app/src/model/Query/ValidatorsMulti/index.ts
+++ b/packages/app/src/model/Query/ValidatorsMulti/index.ts
@@ -16,7 +16,8 @@ export class ValidatorsMulti {
async fetch() {
try {
const result = await this.#pApi.query.Staking.Validators.getValues(
- this.#addresses
+ this.#addresses,
+ { at: 'best' }
);
return result;
} catch (e) {
diff --git a/packages/app/src/model/Subscribe/AccountBalances/index.ts b/packages/app/src/model/Subscribe/AccountBalances/index.ts
index 612124f6a..eaf52d1c9 100644
--- a/packages/app/src/model/Subscribe/AccountBalances/index.ts
+++ b/packages/app/src/model/Subscribe/AccountBalances/index.ts
@@ -196,7 +196,8 @@ export class AccountBalances implements Unsubscribable {
const apiResult = await pApi.apis.NominationPoolsApi.points_to_balance(
poolMembers.pool_id,
- poolMembers.points
+ poolMembers.points,
+ { at: 'best' }
);
const balance = new BigNumber(apiResult?.toString() || 0);
const claimPermission = claimPermissionResult?.type || 'Permissioned';
From 853e5b97b620da01ad401445073c88ad675dab77 Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Thu, 21 Nov 2024 17:38:43 +0700
Subject: [PATCH 67/84] some vault boilerplate
---
.../src/hooks/useSubmitExtrinsic/index.tsx | 54 +++++++---
.../app/src/library/QRCode/DisplayPayload.tsx | 18 ++--
.../app/src/library/Signers/LedgerSigner.ts | 29 ++----
.../app/src/library/Signers/VaultSigner.ts | 98 +++++++++++++++++++
packages/app/src/library/Signers/util.ts | 43 ++++++++
.../SubmitTx/ManualSign/Vault/SignPrompt.tsx | 32 +++---
.../SubmitTx/ManualSign/Vault/index.tsx | 18 ++--
packages/app/src/library/SubmitTx/types.ts | 2 +
8 files changed, 222 insertions(+), 72 deletions(-)
create mode 100644 packages/app/src/library/Signers/VaultSigner.ts
create mode 100644 packages/app/src/library/Signers/util.ts
diff --git a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
index 279e69bbb..4ddebe6af 100644
--- a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
+++ b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
@@ -27,6 +27,9 @@ import { formatAccountSs58 } from '@w3ux/utils';
import { LedgerSigner } from 'library/Signers/LedgerSigner';
import { getLedgerApp } from 'contexts/LedgerHardware/Utils';
import type { LedgerAccount } from '@w3ux/react-connect-kit/types';
+import { VaultSigner } from 'library/Signers/VaultSigner';
+import { usePrompt } from 'contexts/Prompt';
+import { SignPrompt } from 'library/SubmitTx/ManualSign/Vault/SignPrompt';
export const useSubmitExtrinsic = ({
tx,
@@ -44,6 +47,7 @@ export const useSubmitExtrinsic = ({
const { activeProxy } = useActiveAccounts();
const { extensionsStatus } = useExtensions();
const { isProxySupported } = useProxySupported();
+ const { openPromptWith, closePrompt } = usePrompt();
const { handleResetLedgerTask } = useLedgerHardware();
const { addPendingNonce, removePendingNonce } = useTxMeta();
const { getAccount, requiresManualSign } = useImportedAccounts();
@@ -227,21 +231,43 @@ export const useSubmitExtrinsic = ({
// handle signed transaction.
let signer: PolkadotSigner | undefined;
if (requiresManualSign(fromRef.current)) {
- if (source === 'ledger') {
- // Ledger signer.
- signer = await new LedgerSigner(
- AccountId().enc(fromRef.current),
- getLedgerApp(network).txMetadataChainId
- ).getPolkadotSigner(
- {
- decimals: units,
- tokenSymbol: unit,
- },
- (account as LedgerAccount).index
- );
+ const pubKey = AccountId().enc(fromRef.current);
+ const networkInfo = {
+ decimals: units,
+ tokenSymbol: unit,
+ };
+
+ switch (source) {
+ case 'ledger':
+ signer = await new LedgerSigner(
+ pubKey,
+ getLedgerApp(network).txMetadataChainId
+ ).getPolkadotSigner(networkInfo, (account as LedgerAccount).index);
+ break;
+
+ case 'vault':
+ signer = await new VaultSigner(pubKey, {
+ openPrompt: (
+ onComplete: (result: Uint8Array) => void,
+ toSign: Uint8Array
+ ) => {
+ openPromptWith(
+ ,
+ 'small'
+ );
+ },
+ closePrompt: () => closePrompt(),
+ }).getPolkadotSigner(networkInfo);
+ break;
+
+ case 'wallet_connect':
+ // TODO: Implement
+ break;
}
-
- // TODO: Get Vault & Wallet Connect signers.
} else {
// Get the polkadot signer for this account.
signer = (await connectInjectedExtension(source))
diff --git a/packages/app/src/library/QRCode/DisplayPayload.tsx b/packages/app/src/library/QRCode/DisplayPayload.tsx
index 3fcf5f5fa..d4b45f689 100644
--- a/packages/app/src/library/QRCode/DisplayPayload.tsx
+++ b/packages/app/src/library/QRCode/DisplayPayload.tsx
@@ -5,27 +5,23 @@ import type { ReactElement } from 'react';
import { memo, useMemo } from 'react';
import { QrDisplay } from './Display.js';
import type { DisplayPayloadProps } from './types.js';
-import { u8aConcat } from '@polkadot/util';
-import { decodeAddress } from '@polkadot/util-crypto';
+import { AccountId } from 'polkadot-api';
+import { mergeUint8 } from 'polkadot-api/utils';
const createSignPayload = (
address: string,
cmd: number,
payload: Uint8Array,
genesisHash: Uint8Array
-): Uint8Array => {
- const SUBSTRATE_ID = new Uint8Array([0x53]);
- const CRYPTO_SR25519 = new Uint8Array([0x01]);
-
- return u8aConcat(
- SUBSTRATE_ID,
- CRYPTO_SR25519,
+): Uint8Array =>
+ mergeUint8(
+ new Uint8Array([0x53]), // SUBSTRATE_ID
+ new Uint8Array([0x01]), // CRYPTO_SR25519
new Uint8Array([cmd]),
- decodeAddress(address),
+ AccountId().enc(address),
payload,
genesisHash
);
-};
const DisplayPayload = ({
address,
diff --git a/packages/app/src/library/Signers/LedgerSigner.ts b/packages/app/src/library/Signers/LedgerSigner.ts
index a1eca9c67..ba544d70c 100644
--- a/packages/app/src/library/Signers/LedgerSigner.ts
+++ b/packages/app/src/library/Signers/LedgerSigner.ts
@@ -8,8 +8,7 @@ import type { V15 } from '@polkadot-api/substrate-bindings';
import { decAnyMetadata } from '@polkadot-api/substrate-bindings';
import { Ledger } from '../../contexts/LedgerHardware/static/ledger';
import { createV4Tx, getSignBytes } from '@polkadot-api/signers-common';
-
-const CheckMetadataHash = 'CheckMetadataHash';
+import { getExtraSignedExtensions } from './util';
export class LedgerSigner {
#publicKey: Uint8Array;
@@ -33,27 +32,13 @@ export class LedgerSigner {
) => {
const merkleizer = merkleizeMetadata(metadata, networkInfo);
const digest = merkleizer.digest();
-
- // NOTE: Assuming metadata is version 15. Could introduce error here for `useSubmitExtrinsic`
- // to handle.
const v15 = decAnyMetadata(metadata).metadata.value as unknown as V15;
-
- // NOTE: Assuming `CheckMetadataHash` signed extension exists in metadata. Could introduce
- // error here for `useSubmitExtrinsic` to handle.
- const extra: Uint8Array[] = [];
- const additionalSigned: Uint8Array[] = [];
- v15.extrinsic.signedExtensions.map(({ identifier }) => {
- if (identifier === CheckMetadataHash) {
- extra.push(Uint8Array.from([1]));
- additionalSigned.push(mergeUint8(Uint8Array.from([1]), digest));
- return;
- }
- const signedExtension = signedExtensions[identifier];
- if (signedExtension) {
- extra.push(signedExtension.value);
- additionalSigned.push(signedExtension.additionalSigned);
- }
- });
+ const { extra, additionalSigned } = getExtraSignedExtensions(
+ v15,
+ digest,
+ signedExtensions,
+ true
+ );
const toSign = mergeUint8(callData, ...extra, ...additionalSigned);
const { signature } = await Ledger.signPayload(
diff --git a/packages/app/src/library/Signers/VaultSigner.ts b/packages/app/src/library/Signers/VaultSigner.ts
new file mode 100644
index 000000000..96998dce5
--- /dev/null
+++ b/packages/app/src/library/Signers/VaultSigner.ts
@@ -0,0 +1,98 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import { createV4Tx, getSignBytes } from '@polkadot-api/signers-common';
+import type { V15 } from '@polkadot-api/substrate-bindings';
+import { decAnyMetadata } from '@polkadot-api/substrate-bindings';
+import type { PolkadotSigner } from 'polkadot-api';
+import { mergeUint8 } from 'polkadot-api/utils';
+import type { AnyApi } from 'types';
+
+export class VaultSigner {
+ #publicKey: Uint8Array;
+ #promptHandlers: {
+ openPrompt: (
+ onComplete: (result: Uint8Array) => void,
+ toSign: Uint8Array
+ ) => void;
+ closePrompt: () => void;
+ };
+
+ constructor(
+ pubKey: Uint8Array,
+ promptHandlers: { openPrompt: AnyApi; closePrompt: AnyApi }
+ ) {
+ this.#publicKey = pubKey;
+ this.#promptHandlers = promptHandlers;
+ }
+
+ #showPrompt = (toSign: Uint8Array) =>
+ new Promise((resolve) => {
+ const handleComplete = (result: Uint8Array) => {
+ this.#promptHandlers.closePrompt();
+ resolve(result);
+ };
+ // Show prompt, passing completion handler to call once user has completed signing. This will
+ // resolve the promise and continue with signing.
+ this.#promptHandlers.openPrompt(
+ (result: Uint8Array) => handleComplete(result),
+ toSign
+ );
+ });
+
+ async getPolkadotSigner(networkInfo: {
+ decimals: number;
+ tokenSymbol: string;
+ }): Promise {
+ const signTx: PolkadotSigner['signTx'] = async (
+ callData,
+ signedExtensions,
+ metadata
+ ) => {
+ console.debug(networkInfo);
+ // const merkleizer = merkleizeMetadata(metadata, networkInfo);
+ // const digest = merkleizer.digest();
+ const v15 = decAnyMetadata(metadata).metadata.value as unknown as V15;
+
+ const extra: Uint8Array[] = [];
+ const additionalSigned: Uint8Array[] = [];
+ v15.extrinsic.signedExtensions.map(({ identifier }) => {
+ const signedExtension = signedExtensions[identifier];
+ if (!signedExtension) {
+ throw new Error(`Missing ${identifier} signed extension`);
+ }
+ extra.push(signedExtension.value);
+ additionalSigned.push(signedExtension.additionalSigned);
+ });
+
+ const prefix = new Uint8Array([8]);
+ const toSign = mergeUint8(
+ prefix,
+ callData,
+ ...extra,
+ ...additionalSigned
+ );
+
+ // Start flow to sign QR Code here.
+ const userResponse = await this.#showPrompt(toSign);
+
+ console.log('user response: ', userResponse);
+ // NOTE: Placeholder.
+ const signature = Buffer.from(new Uint8Array(0));
+ return createV4Tx(v15, this.#publicKey, signature, extra, callData);
+ };
+
+ return {
+ publicKey: this.#publicKey,
+ signTx,
+ signBytes: getSignBytes(async (x) => {
+ const signature = Buffer.from(x);
+ // TODO: Replace with vault signature.
+ // const { signature } = await Ledger.signPayload(app, index, x);
+ // NOTE: the signature includes a "0x00" at the beginning, indicating a ed25519 signature.
+ // this is not needed for non-extrinsic signatures.
+ return signature.subarray(1);
+ }),
+ };
+ }
+}
diff --git a/packages/app/src/library/Signers/util.ts b/packages/app/src/library/Signers/util.ts
new file mode 100644
index 000000000..f1ff80394
--- /dev/null
+++ b/packages/app/src/library/Signers/util.ts
@@ -0,0 +1,43 @@
+// Copyright 2024 @polkadot-cloud/polkadot-staking-dashboard authors & contributors
+// SPDX-License-Identifier: GPL-3.0-only
+
+import type { V15 } from '@polkadot-api/substrate-bindings';
+import { mergeUint8 } from 'polkadot-api/utils';
+
+const CheckMetadataHash = 'CheckMetadataHash';
+
+export const getExtraSignedExtensions = (
+ v15: V15,
+ digest: Uint8Array,
+ signedExtensions: Record<
+ string,
+ {
+ identifier: string;
+ value: Uint8Array;
+ additionalSigned: Uint8Array;
+ }
+ >,
+ checkMetadataHash = false
+): {
+ extra: Uint8Array[];
+ additionalSigned: Uint8Array[];
+} => {
+ // NOTE: Assuming `CheckMetadataHash` signed extension exists in metadata. Could introduce
+ // error here for `useSubmitExtrinsic` to handle.
+ const extra: Uint8Array[] = [];
+ const additionalSigned: Uint8Array[] = [];
+ v15.extrinsic.signedExtensions.map(({ identifier }) => {
+ if (checkMetadataHash && identifier === CheckMetadataHash) {
+ extra.push(Uint8Array.from([1]));
+ additionalSigned.push(mergeUint8(Uint8Array.from([1]), digest));
+ return;
+ }
+ const signedExtension = signedExtensions[identifier];
+ if (signedExtension) {
+ extra.push(signedExtension.value);
+ additionalSigned.push(signedExtension.additionalSigned);
+ }
+ });
+
+ return { extra, additionalSigned };
+};
diff --git a/packages/app/src/library/SubmitTx/ManualSign/Vault/SignPrompt.tsx b/packages/app/src/library/SubmitTx/ManualSign/Vault/SignPrompt.tsx
index 984b50016..3f9d6de90 100644
--- a/packages/app/src/library/SubmitTx/ManualSign/Vault/SignPrompt.tsx
+++ b/packages/app/src/library/SubmitTx/ManualSign/Vault/SignPrompt.tsx
@@ -8,22 +8,25 @@ import {
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { usePrompt } from 'contexts/Prompt';
-import { useTxMeta } from 'contexts/TxMeta';
import { QRViewerWrapper } from 'library/Import/Wrappers';
import { QrDisplayPayload } from 'library/QRCode/DisplayPayload';
import { QrScanSignature } from 'library/QRCode/ScanSignature';
import type { SignerPromptProps } from 'library/SubmitTx/types';
import type { AnyJson } from '@w3ux/types';
import { ButtonPrimary, ButtonSecondary } from 'ui-buttons';
+import { Bytes } from '@polkadot-api/substrate-bindings';
+import { useApi } from 'contexts/Api';
-export const SignPrompt = ({ submitAddress }: SignerPromptProps) => {
- const { t } = useTranslation('library');
- const { getTxPayload, setTxSignature } = useTxMeta();
+export const SignPrompt = ({
+ submitAddress,
+ toSign,
+ onComplete,
+}: SignerPromptProps) => {
+ const {
+ chainSpecs: { genesisHash },
+ } = useApi();
- const payload = getTxPayload();
- const payloadU8a = payload?.toU8a();
- const { closePrompt } = usePrompt();
+ const { t } = useTranslation('library');
// Whether user is on sign or submit stage.
const [stage, setStage] = useState(1);
@@ -47,8 +50,8 @@ export const SignPrompt = ({ submitAddress }: SignerPromptProps) => {
@@ -58,8 +61,8 @@ export const SignPrompt = ({ submitAddress }: SignerPromptProps) => {
{
- closePrompt();
- setTxSignature(signature);
+ // TODO: Expand with result `status` of cancelled or complete.
+ onComplete(signature);
}}
/>
@@ -90,7 +93,10 @@ export const SignPrompt = ({ submitAddress }: SignerPromptProps) => {
text={t('cancel')}
lg
marginLeft
- onClick={() => closePrompt()}
+ onClick={() => {
+ // TODO: Expand with result `status` of cancelled or complete.
+ onComplete(new Uint8Array(0));
+ }}
/>
diff --git a/packages/app/src/library/SubmitTx/ManualSign/Vault/index.tsx b/packages/app/src/library/SubmitTx/ManualSign/Vault/index.tsx
index 4ebf1f488..bb4c38fdc 100644
--- a/packages/app/src/library/SubmitTx/ManualSign/Vault/index.tsx
+++ b/packages/app/src/library/SubmitTx/ManualSign/Vault/index.tsx
@@ -9,7 +9,6 @@ import { useTxMeta } from 'contexts/TxMeta';
import { EstimatedTxFee } from 'library/EstimatedTxFee';
import { useImportedAccounts } from 'contexts/Connect/ImportedAccounts';
import type { SubmitProps } from '../../types';
-import { SignPrompt } from './SignPrompt';
import { ButtonSubmit } from 'ui-buttons';
import { ButtonSubmitLarge } from 'library/SubmitTx/ButtonSubmitLarge';
import { appendOrEmpty } from '@w3ux/utils';
@@ -24,9 +23,9 @@ export const Vault = ({
displayFor,
}: SubmitProps & { buttons?: ReactNode[] }) => {
const { t } = useTranslation('library');
+ const { txFeesValid } = useTxMeta();
+ const { status: promptStatus } = usePrompt();
const { accountHasSigner } = useImportedAccounts();
- const { txFeesValid, getTxSignature } = useTxMeta();
- const { openPromptWith, status: promptStatus } = usePrompt();
// The state under which submission is disabled.
const disabled =
@@ -34,20 +33,15 @@ export const Vault = ({
// Format submit button based on whether signature currently exists or submission is ongoing.
let buttonText: string;
- let buttonOnClick: () => void;
let buttonDisabled: boolean;
let buttonPulse: boolean;
- if (getTxSignature() !== null || submitting) {
+ if (submitting) {
buttonText = submitText || '';
- buttonOnClick = onSubmit;
buttonDisabled = disabled;
buttonPulse = !(!valid || promptStatus !== 0);
} else {
- buttonText = promptStatus === 0 ? t('sign') : t('signing');
- buttonOnClick = async () => {
- openPromptWith(, 'small');
- };
+ buttonText = t('sign');
buttonDisabled = disabled || promptStatus !== 0;
buttonPulse = !disabled || promptStatus === 0;
}
@@ -67,14 +61,14 @@ export const Vault = ({
text={buttonText}
iconLeft={faSquarePen}
iconTransform="grow-2"
- onClick={() => buttonOnClick()}
+ onClick={() => onSubmit()}
pulse={buttonPulse}
/>
) : (
diff --git a/packages/app/src/library/SubmitTx/types.ts b/packages/app/src/library/SubmitTx/types.ts
index 353c7f5f1..f47868302 100644
--- a/packages/app/src/library/SubmitTx/types.ts
+++ b/packages/app/src/library/SubmitTx/types.ts
@@ -26,6 +26,8 @@ export interface SubmitProps {
export interface SignerPromptProps {
submitAddress: MaybeAddress;
+ toSign: Uint8Array;
+ onComplete: (result: Uint8Array) => void;
}
export interface LedgerSubmitProps {
From 0c86a59bb7ac3365d7ddfd36c52b3f10d160289f Mon Sep 17 00:00:00 2001
From: Ross Bulat
Date: Fri, 22 Nov 2024 11:26:04 +0700
Subject: [PATCH 68/84] vault prompt behaviour working
---
packages/app/src/contexts/Prompt/defaults.tsx | 4 +-
packages/app/src/contexts/Prompt/index.tsx | 12 +++++-
packages/app/src/contexts/Prompt/types.ts | 8 +++-
.../src/hooks/useSubmitExtrinsic/index.tsx | 7 +++-
packages/app/src/library/Prompt/index.tsx | 18 ++++++++-
.../{VaultSigner.ts => VaultSigner/index.ts} | 37 +++++++++----------
.../src/library/Signers/VaultSigner/types.ts | 13 +++++++
.../SubmitTx/ManualSign/Vault/SignPrompt.tsx | 7 +---
packages/app/src/library/SubmitTx/types.ts | 2 +-
9 files changed, 76 insertions(+), 32 deletions(-)
rename packages/app/src/library/Signers/{VaultSigner.ts => VaultSigner/index.ts} (79%)
create mode 100644 packages/app/src/library/Signers/VaultSigner/types.ts
diff --git a/packages/app/src/contexts/Prompt/defaults.tsx b/packages/app/src/contexts/Prompt/defaults.tsx
index 097ec5ad4..57cdefa93 100644
--- a/packages/app/src/contexts/Prompt/defaults.tsx
+++ b/packages/app/src/contexts/Prompt/defaults.tsx
@@ -6,11 +6,13 @@ import type { PromptContextInterface } from './types';
export const defaultPromptContext: PromptContextInterface = {
setOnClosePrompt: (value) => {},
- openPromptWith: (o, s) => {},
+ openPromptWith: (o, s, c) => {},
closePrompt: () => {},
setStatus: (s) => {},
setPrompt: (d) => {},
+ closeOnOutsideClick: true,
size: 'small',
status: 0,
Prompt: null,
+ setCloseOnOutsideClick: (canClose) => {},
};
diff --git a/packages/app/src/contexts/Prompt/index.tsx b/packages/app/src/contexts/Prompt/index.tsx
index 6f43db4b8..05c492c07 100644
--- a/packages/app/src/contexts/Prompt/index.tsx
+++ b/packages/app/src/contexts/Prompt/index.tsx
@@ -19,6 +19,9 @@ export const PromptProvider = ({ children }: { children: ReactNode }) => {
onClosePrompt: null,
});
+ // Whether prompt can be closed by clicking outside on container.
+ const [closeOnOutsideClick, setCloseOnOutsideClick] = useState(false);
+
const setPrompt = (Prompt: Prompt) => {
setState({
...state,
@@ -33,13 +36,18 @@ export const PromptProvider = ({ children }: { children: ReactNode }) => {
});
};
- const openPromptWith = (Prompt: Prompt, size = 'small') => {
+ const openPromptWith = (
+ Prompt: Prompt,
+ size = 'small',
+ closeOutside = true
+ ) => {
setState({
...state,
size,
Prompt,
status: 1,
});
+ setCloseOnOutsideClick(closeOutside);
};
const closePrompt = () => {
@@ -70,9 +78,11 @@ export const PromptProvider = ({ children }: { children: ReactNode }) => {
closePrompt,
setStatus,
setPrompt,
+ setCloseOnOutsideClick,
size: state.size,
status: state.status,
Prompt: state.Prompt,
+ closeOnOutsideClick,
}}
>
{children}
diff --git a/packages/app/src/contexts/Prompt/types.ts b/packages/app/src/contexts/Prompt/types.ts
index 05869612c..c6b4f797d 100644
--- a/packages/app/src/contexts/Prompt/types.ts
+++ b/packages/app/src/contexts/Prompt/types.ts
@@ -6,13 +6,19 @@ import type { MaybeString } from 'types';
export interface PromptContextInterface {
setOnClosePrompt: (onClosePrompt: (() => void) | null) => void;
- openPromptWith: (o: ReactNode | null, s?: string) => void;
+ openPromptWith: (
+ o: ReactNode | null,
+ s?: string,
+ closeOnOutsideClick?: boolean
+ ) => void;
closePrompt: () => void;
setStatus: (s: number) => void;
setPrompt: (d: MaybeString) => void;
size: string;
status: number;
Prompt: Prompt;
+ closeOnOutsideClick: boolean;
+ setCloseOnOutsideClick: (canClose: boolean) => void;
}
export interface PromptState {
diff --git a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
index 4ddebe6af..8e30bac78 100644
--- a/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
+++ b/packages/app/src/hooks/useSubmitExtrinsic/index.tsx
@@ -30,6 +30,7 @@ import type { LedgerAccount } from '@w3ux/react-connect-kit/types';
import { VaultSigner } from 'library/Signers/VaultSigner';
import { usePrompt } from 'contexts/Prompt';
import { SignPrompt } from 'library/SubmitTx/ManualSign/Vault/SignPrompt';
+import type { VaultSignStatus } from 'library/Signers/VaultSigner/types';
export const useSubmitExtrinsic = ({
tx,
@@ -248,7 +249,7 @@ export const useSubmitExtrinsic = ({
case 'vault':
signer = await new VaultSigner(pubKey, {
openPrompt: (
- onComplete: (result: Uint8Array) => void,
+ onComplete: (status: VaultSignStatus, result: Uint8Array) => void,
toSign: Uint8Array
) => {
openPromptWith(
@@ -257,10 +258,12 @@ export const useSubmitExtrinsic = ({
onComplete={onComplete}
toSign={toSign}
/>,
- 'small'
+ 'small',
+ false
);
},
closePrompt: () => closePrompt(),
+ setSubmitting,
}).getPolkadotSigner(networkInfo);
break;
diff --git a/packages/app/src/library/Prompt/index.tsx b/packages/app/src/library/Prompt/index.tsx
index 256ffec57..ab68b535d 100644
--- a/packages/app/src/library/Prompt/index.tsx
+++ b/packages/app/src/library/Prompt/index.tsx
@@ -5,7 +5,13 @@ import { usePrompt } from 'contexts/Prompt';
import { ContentWrapper, HeightWrapper, PromptWrapper } from './Wrappers';
export const Prompt = () => {
- const { closePrompt, size, status, Prompt: PromptInner } = usePrompt();
+ const {
+ size,
+ status,
+ closePrompt,
+ Prompt: PromptInner,
+ closeOnOutsideClick,
+ } = usePrompt();
if (status === 0) {
return null;
@@ -17,7 +23,15 @@ export const Prompt = () => {
{PromptInner}
-