diff --git a/packages/ui/src/components/CallInfo.tsx b/packages/ui/src/components/CallInfo.tsx index b1bd74a0..6ecb82ef 100644 --- a/packages/ui/src/components/CallInfo.tsx +++ b/packages/ui/src/components/CallInfo.tsx @@ -1,7 +1,7 @@ import Expander from './Expander' import { styled } from '@mui/material/styles' import { ReactNode, useMemo } from 'react' -import { ApiDescriptors, IApiContext, useApi } from '../contexts/ApiContext' +import { IApiContext, useApi } from '../contexts/ApiContext' import { getExtrinsicName } from '../utils/getExtrinsicName' import { isProxyCall } from '../utils/isProxyCall' import { formatBigIntBalance } from '../utils/formatBnBalance' @@ -14,6 +14,7 @@ import { JSONprint } from '../utils/jsonPrint' import { Transaction } from 'polkadot-api' import MultisigCompactDisplay from './MultisigCompactDisplay' import { ChainInfoHuman } from '../contexts/PeopleChainApiContext' +import { ApiDescriptors } from '../types' interface Props { aggregatedData: Omit diff --git a/packages/ui/src/components/EasySetup/BalancesTransfer.tsx b/packages/ui/src/components/EasySetup/BalancesTransfer.tsx index 41c309f5..8ccb35d2 100644 --- a/packages/ui/src/components/EasySetup/BalancesTransfer.tsx +++ b/packages/ui/src/components/EasySetup/BalancesTransfer.tsx @@ -2,7 +2,7 @@ import { Box, InputAdornment } from '@mui/material' import { styled } from '@mui/material/styles' import GenericAccountSelection, { AccountBaseInfo } from '../select/GenericAccountSelection' import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react' -import { useApi } from '../../contexts/ApiContext' +import { isContextIn, isContextOf, useApi } from '../../contexts/ApiContext' import { useCheckBalance } from '../../hooks/useCheckBalance' import { inputToBigInt, getGlobalMaxValue } from '../../utils/bnUtils' import { TextField } from '../library' @@ -11,6 +11,7 @@ import { useAccountBaseFromAccountList } from '../../hooks/useAccountBaseFromAcc import { MultiAddress } from '@polkadot-api/descriptors' import { Transaction } from 'polkadot-api' import { useNetwork } from '../../contexts/NetworkContext' +import { noHydrationKeys } from '../../types' interface Props { className?: string @@ -22,7 +23,8 @@ interface Props { const BalancesTransfer = ({ className, onSetExtrinsic, onSetErrorMessage, from }: Props) => { const accountBase = useAccountBaseFromAccountList({ withAccountsFromAddressBook: true }) const [selected, setSelected] = useState() - const { api, chainInfo, apiDescriptor } = useApi() + const ctx = useApi() + const { api, chainInfo, apiDescriptor } = ctx const [amountString, setAmountString] = useState('') const [amount, setAmount] = useState() const [amountError, setAmountError] = useState('') @@ -43,7 +45,7 @@ const BalancesTransfer = ({ className, onSetExtrinsic, onSetErrorMessage, from } }, [amount, amountError, hasEnoughFreeBalance, onSetErrorMessage]) useEffect(() => { - if (!api || !selectedNetwork) { + if (!ctx?.api || !api || !selectedNetwork) { onSetExtrinsic(undefined) return } @@ -53,19 +55,19 @@ const BalancesTransfer = ({ className, onSetExtrinsic, onSetErrorMessage, from } return } - const extrinsic = - apiDescriptor === 'hydration' - ? api.tx.Balances.transfer_keep_alive({ - dest: toAddress, - value: amount - }) - : api.tx.Balances.transfer_keep_alive({ - dest: MultiAddress.Id(toAddress), - value: amount - }) - - onSetExtrinsic(extrinsic) - }, [amount, api, apiDescriptor, chainInfo, onSetExtrinsic, selectedNetwork, toAddress]) + const extrinsic = isContextOf(ctx, 'hydration') + ? ctx.api.tx.Balances.transfer_keep_alive({ + dest: toAddress, + value: amount + }) + : isContextIn(ctx, noHydrationKeys) && + ctx.api.tx.Balances.transfer_keep_alive({ + dest: MultiAddress.Id(toAddress), + value: amount + }) + + !!extrinsic && onSetExtrinsic(extrinsic) + }, [amount, api, apiDescriptor, chainInfo, ctx, onSetExtrinsic, selectedNetwork, toAddress]) const onAddressDestChange = useCallback((account: AccountBaseInfo) => { setSelected(account) diff --git a/packages/ui/src/components/modals/ChangeMultisig.tsx b/packages/ui/src/components/modals/ChangeMultisig.tsx index 1a1974f4..7418f0c3 100644 --- a/packages/ui/src/components/modals/ChangeMultisig.tsx +++ b/packages/ui/src/components/modals/ChangeMultisig.tsx @@ -14,16 +14,10 @@ import AccountDisplay from '../AccountDisplay/AccountDisplay' import ThresholdSelection from '../../pages/Creation/ThresholdSelection' import SignatorySelection from '../select/SignatorySelection' import Summary from '../../pages/Creation/Summary' -import { - isContextIn, - isContextOf, - noHydrationKeys_1, - noHydrationKeys_2, - useApi -} from '../../contexts/ApiContext' +import { isContextIn, isContextOf, useApi } from '../../contexts/ApiContext' import { useAccounts } from '../../contexts/AccountsContext' import { useSigningCallback } from '../../hooks/useSigningCallback' -import { AccountBadge } from '../../types' +import { AccountBadge, noHydrationKeys_1, noHydrationKeys_2, noHydrationKeys_3 } from '../../types' import { getIntersection } from '../../utils/arrayUtils' import GenericAccountSelection, { AccountBaseInfo } from '../select/GenericAccountSelection' import { useProxyAdditionNeededFunds } from '../../hooks/useProxyAdditionNeededFunds' @@ -141,12 +135,18 @@ const ChangeMultisig = ({ onClose, className }: Props) => { proxy_type: Enum('Any'), delay: 0 }) - : isContextIn(ctx, noHydrationKeys_2) && - ctx.api.tx.Proxy.add_proxy({ - delegate: MultiAddress.Id(newMultisigAddress), - proxy_type: Enum('Any'), - delay: 0 - }) + : isContextIn(ctx, noHydrationKeys_2) + ? ctx.api.tx.Proxy.add_proxy({ + delegate: MultiAddress.Id(newMultisigAddress), + proxy_type: Enum('Any'), + delay: 0 + }) + : isContextIn(ctx, noHydrationKeys_3) && + ctx.api.tx.Proxy.add_proxy({ + delegate: MultiAddress.Id(newMultisigAddress), + proxy_type: Enum('Any'), + delay: 0 + }) if (!addProxyTx) return @@ -162,12 +162,18 @@ const ChangeMultisig = ({ onClose, className }: Props) => { force_proxy_type: undefined, call: addProxyTx.decodedCall }) - : isContextIn(ctx, noHydrationKeys_2) && - ctx.api.tx.Proxy.proxy({ - real: MultiAddress.Id(selectedMultiProxy?.proxy), - force_proxy_type: undefined, - call: addProxyTx.decodedCall - }) + : isContextIn(ctx, noHydrationKeys_2) + ? ctx.api.tx.Proxy.proxy({ + real: MultiAddress.Id(selectedMultiProxy?.proxy), + force_proxy_type: undefined, + call: addProxyTx.decodedCall + }) + : isContextIn(ctx, noHydrationKeys_3) && + ctx.api.tx.Proxy.proxy({ + real: MultiAddress.Id(selectedMultiProxy?.proxy), + force_proxy_type: undefined, + call: addProxyTx.decodedCall + }) if (!proxyTx) return @@ -257,12 +263,18 @@ const ChangeMultisig = ({ onClose, className }: Props) => { force_proxy_type: undefined, call: removeProxyTx.decodedCall }) - : isContextIn(ctx, noHydrationKeys_2) && - api.tx.Proxy.proxy({ - real: MultiAddress.Id(selectedMultiProxy?.proxy), - force_proxy_type: undefined, - call: removeProxyTx.decodedCall - }) + : isContextIn(ctx, noHydrationKeys_2) + ? ctx.api.tx.Proxy.proxy({ + real: MultiAddress.Id(selectedMultiProxy?.proxy), + force_proxy_type: undefined, + call: removeProxyTx.decodedCall + }) + : isContextIn(ctx, noHydrationKeys_3) && + ctx.api.tx.Proxy.proxy({ + real: MultiAddress.Id(selectedMultiProxy?.proxy), + force_proxy_type: undefined, + call: removeProxyTx.decodedCall + }) if (!proxyTx) return diff --git a/packages/ui/src/constants.ts b/packages/ui/src/constants.ts index 5e36a910..81bfe8c8 100644 --- a/packages/ui/src/constants.ts +++ b/packages/ui/src/constants.ts @@ -22,7 +22,7 @@ import { nodesCoretimeSVG } from './logos/coretimeSVG' import { polimecSVG } from './logos/polimecSVG' import usdc from './logos/usdc.svg' import usdt from './logos/usdt.svg' -import { DESCRIPTORS } from './contexts/ApiContext' +import { DESCRIPTORS } from './types' export const DAPP_NAME = 'Multix' export const ICON_SIZE_LARGE = 92 diff --git a/packages/ui/src/contexts/ApiContext.tsx b/packages/ui/src/contexts/ApiContext.tsx index 049bb1b0..e5f2d767 100644 --- a/packages/ui/src/contexts/ApiContext.tsx +++ b/packages/ui/src/contexts/ApiContext.tsx @@ -5,70 +5,7 @@ import { ethereumChains } from '../utils/ethereumChains' import { CompatibilityToken, createClient, PolkadotClient, TypedApi } from 'polkadot-api' import { getWsProvider } from 'polkadot-api/ws-provider/web' import { withPolkadotSdkCompat } from 'polkadot-api/polkadot-sdk-compat' -import { - acala, - bifrostDot, - dot, - dotAssetHub, - hydration, - khala, - ksm, - ksmAssetHub, - paseo, - phala, - polimec, - coretimeDot, - westend -} from '@polkadot-api/descriptors' - -export const DESCRIPTORS = { - acala, - bifrostDot, - dot, - dotAssetHub, - hydration, - khala, - ksm, - ksmAssetHub, - paseo, - phala, - polimec, - coretimeDot, - westend -} as const - -export const DESCRIPTORS_NOT_HYDRATION_1 = { - acala, - bifrostDot, - dot, - dotAssetHub, - khala, - phala, - paseo, - polimec -} as const - -export const DESCRIPTORS_NOT_HYDRATION_2 = { - ksm, - ksmAssetHub, - coretimeDot, - westend -} as const - -export type ApiDescriptors = keyof typeof DESCRIPTORS -export type ApiDescriptorsNotHydration_1 = keyof typeof DESCRIPTORS_NOT_HYDRATION_1 -export type ApiDescriptorsNotHydration_2 = keyof typeof DESCRIPTORS_NOT_HYDRATION_1 - -export type Descriptors = (typeof DESCRIPTORS)[Id] -type ApiOf = TypedApi> - -export const noHydrationKeys_1 = Object.keys( - DESCRIPTORS_NOT_HYDRATION_1 -) as ApiDescriptorsNotHydration_1[] - -export const noHydrationKeys_2 = Object.keys( - DESCRIPTORS_NOT_HYDRATION_2 -) as ApiDescriptorsNotHydration_2[] +import { ApiDescriptors, ApiOf, Descriptors, DESCRIPTORS } from '../types' type ApiContextProps = { children: React.ReactNode | React.ReactNode[] diff --git a/packages/ui/src/hooks/useGetAssetBalance.tsx b/packages/ui/src/hooks/useGetAssetBalance.tsx index 9adf4488..06553a45 100644 --- a/packages/ui/src/hooks/useGetAssetBalance.tsx +++ b/packages/ui/src/hooks/useGetAssetBalance.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from 'react' -import { useApi } from '../contexts/ApiContext' +import { isContextIn, useApi } from '../contexts/ApiContext' import { formatBigIntBalance } from '../utils/formatBnBalance' -import { dotAssetHub, DotAssetHubQueries } from '@polkadot-api/descriptors' -import { TypedApi } from 'polkadot-api' +import { DotAssetHubQueries } from '@polkadot-api/descriptors' +import { assetHubKeys } from '../types' interface useGetBalanceProps { address?: string @@ -15,7 +15,7 @@ export const useGetAssetBalance = ({ numberAfterComma = 4, assetId }: useGetBalanceProps) => { - const { api } = useApi() + const ctx = useApi() const [balance, setBalance] = useState(null) const [balanceFormatted, setFormattedBalance] = useState(null) const [assetMetadata, setAssetMetadata] = useState< @@ -23,33 +23,30 @@ export const useGetAssetBalance = ({ >(null) useEffect(() => { - if (!api || !assetId) return - ;(api as TypedApi).query.Assets.Metadata.getValue(assetId) - .then(setAssetMetadata) - .catch(console.error) - }, [api, assetId]) + if (!ctx?.api || !isContextIn(ctx, assetHubKeys) || !assetId) return + ctx.api.query.Assets.Metadata.getValue(assetId).then(setAssetMetadata).catch(console.error) + }, [ctx, assetId]) useEffect(() => { - if (!api || !address || !assetMetadata || !assetId) return - - const unsub = (api as TypedApi).query.Assets.Account.watchValue( - assetId, - address, - 'best' - ).subscribe((res) => { - const balance = res?.balance || 0n - - setBalance(balance) - setFormattedBalance( - formatBigIntBalance(balance, assetMetadata.decimals, { - numberAfterComma, - tokenSymbol: assetMetadata.symbol.asText() - }) - ) - }) + if (!ctx?.api || !isContextIn(ctx, assetHubKeys) || !address || !assetMetadata || !assetId) + return + + const unsub = ctx.api.query.Assets.Account.watchValue(assetId, address, 'best').subscribe( + (res) => { + const balance = res?.balance || 0n + + setBalance(balance) + setFormattedBalance( + formatBigIntBalance(balance, assetMetadata.decimals, { + numberAfterComma, + tokenSymbol: assetMetadata.symbol.asText() + }) + ) + } + ) return () => unsub && unsub.unsubscribe() - }, [address, api, assetId, assetMetadata, numberAfterComma]) + }, [address, assetId, assetMetadata, ctx, numberAfterComma]) return { balance, balanceFormatted } } diff --git a/packages/ui/src/hooks/useGetIdentity.tsx b/packages/ui/src/hooks/useGetIdentity.tsx index 0a336a4e..294780bf 100644 --- a/packages/ui/src/hooks/useGetIdentity.tsx +++ b/packages/ui/src/hooks/useGetIdentity.tsx @@ -1,5 +1,5 @@ import { useCallback } from 'react' -import { useIdenityApi } from './useIdentityApi' +import { useIdentityApi } from './useIdentityApi' import { FixedSizeBinary, TypedApi } from 'polkadot-api' import { dotPpl, IdentityData, IdentityJudgement } from '@polkadot-api/descriptors' @@ -9,7 +9,7 @@ export interface IdentityInfo extends Record { } export const useGetIdentity = () => { - const { api } = useIdenityApi() + const { api } = useIdentityApi() const getIdentity = useCallback( async (address: string) => { diff --git a/packages/ui/src/hooks/useGetMultisigTx.tsx b/packages/ui/src/hooks/useGetMultisigTx.tsx index 891caaa3..3eb234f0 100644 --- a/packages/ui/src/hooks/useGetMultisigTx.tsx +++ b/packages/ui/src/hooks/useGetMultisigTx.tsx @@ -1,12 +1,18 @@ import { useMemo } from 'react' -import { useApi } from '../contexts/ApiContext' +import { isContextIn, isContextOf, useApi } from '../contexts/ApiContext' import { MultiProxy } from '../contexts/MultiProxyContext' import { useGetSortAddress } from './useGetSortAddress' import { getAsMultiTx } from '../utils/getAsMultiTx' -import { MultisigStorageInfo, Weight } from '../types' +import { + MultisigStorageInfo, + noHydrationKeys_1, + noHydrationKeys_2, + noHydrationKeys_3, + Weight +} from '../types' import { getApproveAsMultiTx } from '../utils/getApproveAsMultiTx' -import { HexString, Transaction, TypedApi } from 'polkadot-api' -import { dot, hydration, MultiAddress } from '@polkadot-api/descriptors' +import { HexString, Transaction } from 'polkadot-api' +import { MultiAddress } from '@polkadot-api/descriptors' import { useNetwork } from '../contexts/NetworkContext' interface Params { @@ -36,7 +42,8 @@ export const useGetMultisigTx = ({ forceAsMulti = true, approveAsMultiHash }: Params) => { - const { api, compatibilityToken } = useApi() + const ctx = useApi() + const { api, compatibilityToken } = ctx const { getSortAddress } = useGetSortAddress() const { selectedNetwork } = useNetwork() @@ -54,7 +61,7 @@ export const useGetMultisigTx = ({ return } - if (!api || !selectedNetwork) { + if (!ctx?.api || !selectedNetwork) { return } @@ -82,28 +89,42 @@ export const useGetMultisigTx = ({ return } - let tx: Transaction | undefined + let tx: Transaction | false | undefined try { // the proxy is selected if (isProxy && !!extrinsicToCall) { - tx = - selectedNetwork === 'hydration' - ? (api as TypedApi).tx.Proxy.proxy({ - real: fromAddress, - force_proxy_type: undefined, - call: extrinsicToCall.decodedCall - }) - : (api as TypedApi).tx.Proxy.proxy({ + tx = isContextOf(ctx, 'hydration') + ? ctx.api.tx.Proxy.proxy({ + real: fromAddress, + force_proxy_type: undefined, + call: extrinsicToCall.decodedCall + }) + : isContextIn(ctx, noHydrationKeys_1) + ? ctx.api.tx.Proxy.proxy({ real: MultiAddress.Id(fromAddress), force_proxy_type: undefined, call: extrinsicToCall.decodedCall }) + : isContextIn(ctx, noHydrationKeys_2) + ? ctx.api.tx.Proxy.proxy({ + real: MultiAddress.Id(fromAddress), + force_proxy_type: undefined, + call: extrinsicToCall.decodedCall + }) + : isContextIn(ctx, noHydrationKeys_3) && + ctx.api.tx.Proxy.proxy({ + real: MultiAddress.Id(fromAddress), + force_proxy_type: undefined, + call: extrinsicToCall.decodedCall + }) // a multisig is selected } else { tx = extrinsicToCall } + if (!tx) return + return forceAsMulti || approvalLength >= threshold - 1 ? getAsMultiTx({ api, threshold, otherSignatories, tx, weight, when, compatibilityToken }) : getApproveAsMultiTx({ @@ -121,7 +142,7 @@ export const useGetMultisigTx = ({ selectedMultisig, getSortAddress, threshold, - api, + ctx, selectedNetwork, senderAddress, fromAddress, @@ -130,6 +151,7 @@ export const useGetMultisigTx = ({ approvalLength, approveAsMultiHash, isProxy, + api, weight, when, compatibilityToken diff --git a/packages/ui/src/hooks/useHasIdentityFeature.tsx b/packages/ui/src/hooks/useHasIdentityFeature.tsx index 9931a6c8..00566f58 100644 --- a/packages/ui/src/hooks/useHasIdentityFeature.tsx +++ b/packages/ui/src/hooks/useHasIdentityFeature.tsx @@ -1,11 +1,11 @@ import { useMemo } from 'react' import { useNetwork } from '../contexts/NetworkContext' -import { useIdenityApi } from './useIdentityApi' +import { useIdentityApi } from './useIdentityApi' import { dotPpl } from '@polkadot-api/descriptors' import { TypedApi } from 'polkadot-api' export const useHasIdentityFeature = () => { - const { api } = useIdenityApi() + const { api } = useIdentityApi() const { selectedNetworkInfo } = useNetwork() const hasIdentityPallet = useMemo( () => !!api && !!(api as TypedApi).tx?.Identity?.set_identity, diff --git a/packages/ui/src/hooks/useIdentityApi.tsx b/packages/ui/src/hooks/useIdentityApi.tsx index cb6ac383..bc6cf63e 100644 --- a/packages/ui/src/hooks/useIdentityApi.tsx +++ b/packages/ui/src/hooks/useIdentityApi.tsx @@ -1,8 +1,9 @@ import { useState, useEffect } from 'react' import { ChainInfoHuman, IPplApiContext, usePplApi } from '../contexts/PeopleChainApiContext' -import { ApiDescriptors, IApiContext, useApi } from '../contexts/ApiContext' +import { IApiContext, useApi } from '../contexts/ApiContext' +import { ApiDescriptors } from '../types' -export const useIdenityApi = () => { +export const useIdentityApi = () => { const { pplApi, pplChainInfo } = usePplApi() const { api, chainInfo } = useApi() const [apiToUse, setApiToUse] = useState< diff --git a/packages/ui/src/hooks/usePendingTx.tsx b/packages/ui/src/hooks/usePendingTx.tsx index db403209..c4f4361a 100644 --- a/packages/ui/src/hooks/usePendingTx.tsx +++ b/packages/ui/src/hooks/usePendingTx.tsx @@ -1,11 +1,11 @@ import { useCallback, useEffect, useState } from 'react' import { useMultiProxy } from '../contexts/MultiProxyContext' -import { MultisigStorageInfo } from '../types' +import { ApiDescriptors, MultisigStorageInfo } from '../types' import { useMultisigCallQuery } from './useQueryMultisigCalls' import { isEmptyArray } from '../utils/arrayUtils' import { isProxyCall } from '../utils/isProxyCall' import { useAccountId } from './useAccountId' -import { ApiDescriptors, IApiContext, useApi } from '../contexts/ApiContext' +import { IApiContext, useApi } from '../contexts/ApiContext' import dayjs from 'dayjs' import localizedFormat from 'dayjs/plugin/localizedFormat' import { PolkadotClient, Transaction } from 'polkadot-api' diff --git a/packages/ui/src/hooks/useProxyAdditionNeededFunds.tsx b/packages/ui/src/hooks/useProxyAdditionNeededFunds.tsx index 1b6a12f7..de9337a2 100644 --- a/packages/ui/src/hooks/useProxyAdditionNeededFunds.tsx +++ b/packages/ui/src/hooks/useProxyAdditionNeededFunds.tsx @@ -1,7 +1,5 @@ import { useEffect, useState } from 'react' import { useApi } from '../contexts/ApiContext' -import { TypedApi } from 'polkadot-api' -import { dot } from '@polkadot-api/descriptors' export const useProxyAdditionNeededFunds = () => { const { api, chainInfo } = useApi() @@ -12,12 +10,9 @@ export const useProxyAdditionNeededFunds = () => { if (!chainInfo?.tokenDecimals) return - if (!(api as TypedApi).constants?.Proxy?.ProxyDepositFactor) - return // the proxy is already created (with proxyDepositBase already deposited by the first account - // that added the first proxy) we are only adding one account as proxy - ;(api as TypedApi).constants.Proxy.ProxyDepositBase() - .then(setMin) - .catch(console.error) + if (!api.constants?.Proxy?.ProxyDepositFactor) return // the proxy is already created (with proxyDepositBase already deposited by the first account + // that added the first proxy) we are only adding one account as proxy + api.constants.Proxy.ProxyDepositBase().then(setMin).catch(console.error) }, [api, chainInfo]) return { proxyAdditionNeededFunds: min } diff --git a/packages/ui/src/hooks/usePureProxyCreationNeededFunds.tsx b/packages/ui/src/hooks/usePureProxyCreationNeededFunds.tsx index 2630ef72..d6be241e 100644 --- a/packages/ui/src/hooks/usePureProxyCreationNeededFunds.tsx +++ b/packages/ui/src/hooks/usePureProxyCreationNeededFunds.tsx @@ -1,7 +1,5 @@ import { useEffect, useState } from 'react' import { useApi } from '../contexts/ApiContext' -import { TypedApi } from 'polkadot-api' -import { dot } from '@polkadot-api/descriptors' export const usePureProxyCreationNeededFunds = () => { const { api, chainInfo, compatibilityToken } = useApi() @@ -11,15 +9,9 @@ export const usePureProxyCreationNeededFunds = () => { useEffect(() => { if (!api || !compatibilityToken) return - const existentialDeposit = (api as TypedApi).constants.Balances.ExistentialDeposit( - compatibilityToken - ) - const depositBase = (api as TypedApi).constants.Proxy.ProxyDepositBase( - compatibilityToken - ) - const depositFactor = (api as TypedApi).constants.Proxy.ProxyDepositFactor( - compatibilityToken - ) + const existentialDeposit = api.constants.Balances.ExistentialDeposit(compatibilityToken) + const depositBase = api.constants.Proxy.ProxyDepositBase(compatibilityToken) + const depositFactor = api.constants.Proxy.ProxyDepositFactor(compatibilityToken) if (!existentialDeposit || !depositBase || !depositFactor) return // if (!chainInfo?.tokenDecimals) return diff --git a/packages/ui/src/hooks/useSetIdentityReservedFunds.tsx b/packages/ui/src/hooks/useSetIdentityReservedFunds.tsx index aa84347c..4345c9c6 100644 --- a/packages/ui/src/hooks/useSetIdentityReservedFunds.tsx +++ b/packages/ui/src/hooks/useSetIdentityReservedFunds.tsx @@ -31,11 +31,11 @@ // if (!chainInfo?.tokenDecimals) return // const byteDeposit = ( -// api as unknown as TypedApi +// api // ).constants?.Identity?.ByteDeposit(compatibilityToken) // const basicDeposit = ( -// api as unknown as TypedApi +// api // ).constants?.Identity.BasicDeposit(compatibilityToken) // if (!basicDeposit || !byteDeposit) return diff --git a/packages/ui/src/pages/Creation/index.tsx b/packages/ui/src/pages/Creation/index.tsx index e8477452..cd216cb0 100644 --- a/packages/ui/src/pages/Creation/index.tsx +++ b/packages/ui/src/pages/Creation/index.tsx @@ -10,7 +10,7 @@ import { import { Button, ButtonWithIcon } from '../../components/library' import { useCallback, useEffect, useMemo, useState } from 'react' import { styled } from '@mui/material/styles' -import { useApi } from '../../contexts/ApiContext' +import { isContextIn, isContextOf, useApi } from '../../contexts/ApiContext' import SignatorySelection from '../../components/select/SignatorySelection' import { useAccounts } from '../../contexts/AccountsContext' import ThresholdSelection from './ThresholdSelection' @@ -28,9 +28,15 @@ import { useGetMultisigAddress } from '../../contexts/useGetMultisigAddress' import { isEthereumAddress } from '@polkadot/util-crypto' import { getAsMultiTx } from '../../utils/getAsMultiTx' import { useMultiProxy } from '../../contexts/MultiProxyContext' -import { Binary, Enum, Transaction, TypedApi } from 'polkadot-api' -import { dot, hydration, MultiAddress } from '@polkadot-api/descriptors' +import { Binary, Enum, Transaction } from 'polkadot-api' +import { MultiAddress } from '@polkadot-api/descriptors' import { useNetwork } from '../../contexts/NetworkContext' +import { + allDescriptorsKey_1_3, + allDescriptorsKey_2_3, + allDescriptorsKey_3_3, + noHydrationKeys +} from '../../types' interface Props { className?: string @@ -42,7 +48,8 @@ const MultisigCreation = ({ className }: Props) => { const [signatories, setSignatories] = useState([]) const [currentStep, setCurrentStep] = useState(0) const isLastStep = useMemo(() => currentStep === steps.length - 1, [currentStep]) - const { api, chainInfo, compatibilityToken } = useApi() + const ctx = useApi() + const { api, chainInfo, compatibilityToken } = ctx const [threshold, setThreshold] = useState() const { selectedAccount, ownAddressList } = useAccounts() const navigate = useNavigate() @@ -73,7 +80,7 @@ const MultisigCreation = ({ className }: Props) => { const { pureProxyCreationNeededFunds, reserved: proxyReserved } = usePureProxyCreationNeededFunds() const supportsProxy = useMemo(() => { - const hasProxyPallet = !!api && !!(api as TypedApi).tx.Proxy + const hasProxyPallet = !!api && !!api.tx.Proxy // Moonbeam and moonriver have the pallet, but it's deactivated return hasProxyPallet && !chainInfo?.isEthereum }, [api, chainInfo]) @@ -148,7 +155,7 @@ const MultisigCreation = ({ className }: Props) => { // this batchCall is only useful if the user wants a proxy. return } - if (!api || !compatibilityToken || !selectedNetwork) { + if (!ctx?.api || !compatibilityToken || !selectedNetwork) { // console.error('api is not ready') return } @@ -175,11 +182,28 @@ const MultisigCreation = ({ className }: Props) => { const otherSignatories = getSortAddress( signatories.filter((sig) => sig !== selectedAccount.address) ) - const proxyTx = (api as TypedApi).tx.Proxy.create_pure({ - proxy_type: Enum('Any'), - delay: 0, - index: 0 - }) + const proxyTx = + (isContextIn(ctx, allDescriptorsKey_1_3) && + ctx.api.tx.Proxy.create_pure({ + proxy_type: Enum('Any'), + delay: 0, + index: 0 + })) || + (isContextIn(ctx, allDescriptorsKey_2_3) && + ctx.api.tx.Proxy.create_pure({ + proxy_type: Enum('Any'), + delay: 0, + index: 0 + })) || + (isContextIn(ctx, allDescriptorsKey_3_3) && + ctx.api.tx.Proxy.create_pure({ + proxy_type: Enum('Any'), + delay: 0, + index: 0 + })) + + if (!proxyTx) return + const multiSigProxyCall = getAsMultiTx({ api, threshold, @@ -189,30 +213,36 @@ const MultisigCreation = ({ className }: Props) => { }) // Some funds are needed on the multisig for the pure proxy creation - const transferTx = - selectedNetwork === 'hydration' - ? (api as TypedApi).tx.Balances.transfer_keep_alive({ - dest: multiAddress, - value: pureProxyCreationNeededFunds - }) - : (api as TypedApi).tx.Balances.transfer_keep_alive({ - dest: MultiAddress.Id(multiAddress), - value: pureProxyCreationNeededFunds - }) + const transferTx = isContextOf(ctx, 'hydration') + ? ctx.api.tx.Balances.transfer_keep_alive({ + dest: multiAddress, + value: pureProxyCreationNeededFunds + }) + : isContextIn(ctx, noHydrationKeys) && + ctx.api.tx.Balances.transfer_keep_alive({ + dest: MultiAddress.Id(multiAddress), + value: pureProxyCreationNeededFunds + }) if (!multiSigProxyCall) { console.error('multiSigProxyCall is undefined in Creation index.tsx') return } + if (!transferTx) { + console.error('transferTx is undefined in Creation index.tsx') + return + } + setBatchCall( - api.tx.Utility.batch_all({ + ctx.api.tx.Utility.batch_all({ calls: [transferTx.decodedCall, multiSigProxyCall.decodedCall] }) ) }, [ api, compatibilityToken, + ctx, getSortAddress, multiAddress, pureProxyCreationNeededFunds, diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts index 96b0b6ac..ddac7e9a 100644 --- a/packages/ui/src/types.ts +++ b/packages/ui/src/types.ts @@ -1,4 +1,4 @@ -import { HexString, SS58String, Transaction } from 'polkadot-api' +import { HexString, SS58String, Transaction, TypedApi } from 'polkadot-api' export interface MultisigStorageInfo { when: { @@ -56,3 +56,101 @@ export interface AccountRegistration { web?: string | undefined judgements: IdentityJudgement[] } + +import { + acala, + bifrostDot, + dot, + dotAssetHub, + hydration, + khala, + ksm, + ksmAssetHub, + paseo, + phala, + polimec, + coretimeDot, + westend +} from '@polkadot-api/descriptors' + +export const DESCRIPTORS = { + acala, + bifrostDot, + dot, + dotAssetHub, + hydration, + khala, + ksm, + ksmAssetHub, + paseo, + phala, + polimec, + coretimeDot, + westend +} as const + +export const DESCRIPTORS_NOT_HYDRATION_1_3 = { + acala, + bifrostDot, + dot, + dotAssetHub +} as const + +export const DESCRIPTORS_NOT_HYDRATION_2_3 = { + khala, + ksm, + ksmAssetHub, + paseo +} as const + +export const DESCRIPTORS_NOT_HYDRATION_3_3 = { + phala, + polimec, + coretimeDot, + westend +} as const + +export const DESCRIPTORS_ASSET_HUBS = { + dotAssetHub, + ksmAssetHub +} + +export const DESCRIPTORS_1_3 = { acala, bifrostDot, dot, dotAssetHub, hydration } as const +export const DESCRIPTORS_2_3 = { khala, ksm, ksmAssetHub, paseo, phala } as const +export const DESCRIPTORS_3_3 = { polimec, coretimeDot, westend } as const + +export type ApiDescriptors = keyof typeof DESCRIPTORS + +export type Descriptors = (typeof DESCRIPTORS)[Id] +export type ApiOf = TypedApi> + +// No hydration +export const noHydrationKeys_1 = Object.keys( + DESCRIPTORS_NOT_HYDRATION_1_3 +) as (keyof typeof DESCRIPTORS_NOT_HYDRATION_1_3)[] + +export const noHydrationKeys_2 = Object.keys( + DESCRIPTORS_NOT_HYDRATION_2_3 +) as (keyof typeof DESCRIPTORS_NOT_HYDRATION_2_3)[] + +export const noHydrationKeys_3 = Object.keys( + DESCRIPTORS_NOT_HYDRATION_3_3 +) as (keyof typeof DESCRIPTORS_NOT_HYDRATION_3_3)[] + +export const noHydrationKeys = [...noHydrationKeys_1, ...noHydrationKeys_2, ...noHydrationKeys_3] + +// All descriptors +export const allDescriptorsKey_1_3 = Object.keys( + DESCRIPTORS_1_3 +) as (keyof typeof DESCRIPTORS_1_3)[] +export const allDescriptorsKey_2_3 = Object.keys( + DESCRIPTORS_2_3 +) as (keyof typeof DESCRIPTORS_2_3)[] +export const allDescriptorsKey_3_3 = Object.keys( + DESCRIPTORS_3_3 +) as (keyof typeof DESCRIPTORS_3_3)[] + +// Asset hubs +export const assetHubKeys = Object.keys( + DESCRIPTORS_ASSET_HUBS +) as (keyof typeof DESCRIPTORS_ASSET_HUBS)[] diff --git a/packages/ui/src/utils/getApproveAsMultiTx.ts b/packages/ui/src/utils/getApproveAsMultiTx.ts index 5c4a8b1c..c0cc9d26 100644 --- a/packages/ui/src/utils/getApproveAsMultiTx.ts +++ b/packages/ui/src/utils/getApproveAsMultiTx.ts @@ -1,6 +1,6 @@ import { FixedSizeBinary, HexString } from 'polkadot-api' -import { ApiDescriptors, IApiContext } from '../contexts/ApiContext' -import { MultisigStorageInfo } from '../types' +import { IApiContext } from '../contexts/ApiContext' +import { ApiDescriptors, MultisigStorageInfo } from '../types' interface Params { api: IApiContext['api'] diff --git a/packages/ui/src/utils/getAsMultiTx.ts b/packages/ui/src/utils/getAsMultiTx.ts index 73768aa7..1b1bfaee 100644 --- a/packages/ui/src/utils/getAsMultiTx.ts +++ b/packages/ui/src/utils/getAsMultiTx.ts @@ -1,6 +1,6 @@ -import { MultisigStorageInfo, Weight } from '../types' +import { ApiDescriptors, MultisigStorageInfo, Weight } from '../types' import { Binary, HexString, Transaction } from 'polkadot-api' -import { ApiDescriptors, IApiContext } from '../contexts/ApiContext' +import { IApiContext } from '../contexts/ApiContext' interface Params { api: IApiContext['api'] diff --git a/packages/ui/src/utils/getEncodedCallFromDecodedTx.ts b/packages/ui/src/utils/getEncodedCallFromDecodedTx.ts index c267ed46..490161f2 100644 --- a/packages/ui/src/utils/getEncodedCallFromDecodedTx.ts +++ b/packages/ui/src/utils/getEncodedCallFromDecodedTx.ts @@ -1,5 +1,6 @@ import { CompatibilityToken, Transaction } from 'polkadot-api' -import { ApiDescriptors, IApiContext } from '../contexts/ApiContext' +import { IApiContext } from '../contexts/ApiContext' +import { ApiDescriptors } from '../types' export const getEncodedCallFromDecodedTx = ( api: IApiContext['api'], diff --git a/packages/ui/src/utils/isNotHydration.ts b/packages/ui/src/utils/isNotHydration.ts deleted file mode 100644 index b22fc667..00000000 --- a/packages/ui/src/utils/isNotHydration.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Transaction } from 'polkadot-api' -import { IApiContext } from '../contexts/ApiContext' - -interface Params { - apiDescriptor: IApiContext['apiDescriptor'] - tx1: Transaction - tx2: Transaction -} - -export const isNotHydration = ({ apiDescriptor, tx1, tx2 }: Params) => { - return apiDescriptor === 'hydration' ? tx1 : tx2 -}