From 8d363e7f7bc0d3f41c62e09105b83c83288cc4da Mon Sep 17 00:00:00 2001 From: Sergey Zhuravlev Date: Mon, 3 Feb 2025 19:34:34 +0100 Subject: [PATCH 1/4] fix: selecting correct asset to xcm transfer title --- .../transaction/ui/TransactionTitle/TransactionTitle.tsx | 1 + .../components/XcmTransferOperationTitle.tsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/entities/transaction/ui/TransactionTitle/TransactionTitle.tsx b/src/renderer/entities/transaction/ui/TransactionTitle/TransactionTitle.tsx index e7a3db5e08..9882f0a4d2 100644 --- a/src/renderer/entities/transaction/ui/TransactionTitle/TransactionTitle.tsx +++ b/src/renderer/entities/transaction/ui/TransactionTitle/TransactionTitle.tsx @@ -11,6 +11,7 @@ type Props = { className?: string; }; +// TODO decompose export const TransactionTitle = ({ tx, className, children }: PropsWithChildren) => { const { t } = useI18n(); diff --git a/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx b/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx index 4c570239d8..f074aba2e2 100644 --- a/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx +++ b/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx @@ -11,7 +11,8 @@ type Props = { export const XcmTransferOperationTitle = ({ operation }: Props) => { const assetId = operation.transaction?.args.assetId || operation.transaction?.args.asset; - const asset = getAssetById(assetId, chainsService.getChainById(operation.chainId)?.assets); + const chainId = operation.transaction?.args.destinationChain || operation.chainId; + const asset = getAssetById(assetId, chainsService.getChainById(chainId)?.assets); const amount = operation.transaction && getTransactionAmount(operation.transaction); From 823ad3bfbc81f8ddb2efe9ed5d1b7dc98aeb68f5 Mon Sep 17 00:00:00 2001 From: asmadek Date: Tue, 4 Feb 2025 04:05:12 +0500 Subject: [PATCH 2/4] fix: use inner transaction for multisig title --- .../components/GovernanceOperationTitle.tsx | 10 +-- .../components/ProxyOperationTitle.tsx | 10 +-- .../components/StakingOperationTitle.tsx | 10 +-- .../components/TransferOperationTitle.tsx | 10 +-- .../components/XcmTransferOperationTitle.tsx | 18 +++--- .../shared/api/xcm/__tests__/mock/xcmData.ts | 63 +++++++++++++++++++ .../api/xcm/__tests__/xcm-service.test.ts | 16 +++++ src/renderer/shared/api/xcm/lib/xcm-utils.ts | 4 +- .../shared/api/xcm/service/xcmService.ts | 23 ++++--- 9 files changed, 128 insertions(+), 36 deletions(-) diff --git a/src/renderer/features/governance-operation-details/components/GovernanceOperationTitle.tsx b/src/renderer/features/governance-operation-details/components/GovernanceOperationTitle.tsx index 0fc27bf6d9..e4d8e05a5d 100644 --- a/src/renderer/features/governance-operation-details/components/GovernanceOperationTitle.tsx +++ b/src/renderer/features/governance-operation-details/components/GovernanceOperationTitle.tsx @@ -4,6 +4,7 @@ import { getAssetById } from '@/shared/lib/utils'; import { Box } from '@/shared/ui-kit'; import { AssetBalance } from '@/entities/asset'; import { ChainTitle } from '@/entities/chain'; +import { getTransactionFromMultisigTx } from '@/entities/multisig'; import { TransactionTitle, getTransactionAmount } from '@/entities/transaction'; type Props = { @@ -11,14 +12,15 @@ type Props = { }; export const GovernanceOperationTitle = ({ operation }: Props) => { + const transaction = getTransactionFromMultisigTx(operation); + const asset = - operation.transaction && - getAssetById(operation.transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); - const amount = operation.transaction && getTransactionAmount(operation.transaction); + transaction && getAssetById(transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); + const amount = transaction && getTransactionAmount(transaction); return ( <> - + {asset && amount && ( diff --git a/src/renderer/features/proxy-operation-details/components/ProxyOperationTitle.tsx b/src/renderer/features/proxy-operation-details/components/ProxyOperationTitle.tsx index 51869e8240..395176e1cf 100644 --- a/src/renderer/features/proxy-operation-details/components/ProxyOperationTitle.tsx +++ b/src/renderer/features/proxy-operation-details/components/ProxyOperationTitle.tsx @@ -3,6 +3,7 @@ import { type MultisigTransaction } from '@/shared/core'; import { getAssetById } from '@/shared/lib/utils'; import { AssetBalance } from '@/entities/asset'; import { ChainTitle } from '@/entities/chain'; +import { getTransactionFromMultisigTx } from '@/entities/multisig'; import { TransactionTitle, getTransactionAmount } from '@/entities/transaction'; type Props = { @@ -10,14 +11,15 @@ type Props = { }; export const ProxyOperationTitle = ({ operation }: Props) => { + const transaction = getTransactionFromMultisigTx(operation); + const asset = - operation.transaction && - getAssetById(operation.transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); - const amount = operation.transaction && getTransactionAmount(operation.transaction); + transaction && getAssetById(transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); + const amount = transaction && getTransactionAmount(transaction); return ( <> - + {asset && amount && (
diff --git a/src/renderer/features/staking-operation-details/components/StakingOperationTitle.tsx b/src/renderer/features/staking-operation-details/components/StakingOperationTitle.tsx index 09c5603671..cef5a642a5 100644 --- a/src/renderer/features/staking-operation-details/components/StakingOperationTitle.tsx +++ b/src/renderer/features/staking-operation-details/components/StakingOperationTitle.tsx @@ -3,6 +3,7 @@ import { type MultisigTransaction } from '@/shared/core'; import { getAssetById } from '@/shared/lib/utils'; import { AssetBalance } from '@/entities/asset'; import { ChainTitle } from '@/entities/chain'; +import { getTransactionFromMultisigTx } from '@/entities/multisig'; import { TransactionTitle, getTransactionAmount } from '@/entities/transaction'; type Props = { @@ -10,14 +11,15 @@ type Props = { }; export const StakingOperationTitle = ({ operation }: Props) => { + const transaction = getTransactionFromMultisigTx(operation); + const asset = - operation.transaction && - getAssetById(operation.transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); - const amount = operation.transaction && getTransactionAmount(operation.transaction); + transaction && getAssetById(transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); + const amount = transaction && getTransactionAmount(transaction); return ( <> - + {asset && amount && (
diff --git a/src/renderer/features/transfer-operation-details/components/TransferOperationTitle.tsx b/src/renderer/features/transfer-operation-details/components/TransferOperationTitle.tsx index 2e602bbb76..ba8deee576 100644 --- a/src/renderer/features/transfer-operation-details/components/TransferOperationTitle.tsx +++ b/src/renderer/features/transfer-operation-details/components/TransferOperationTitle.tsx @@ -3,6 +3,7 @@ import { type MultisigTransaction } from '@/shared/core'; import { getAssetById } from '@/shared/lib/utils'; import { AssetBalance } from '@/entities/asset'; import { ChainTitle } from '@/entities/chain'; +import { getTransactionFromMultisigTx } from '@/entities/multisig'; import { TransactionTitle, getTransactionAmount } from '@/entities/transaction'; type Props = { @@ -10,14 +11,15 @@ type Props = { }; export const TransferOperationTitle = ({ operation }: Props) => { + const transaction = getTransactionFromMultisigTx(operation); + const asset = - operation.transaction && - getAssetById(operation.transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); - const amount = operation.transaction && getTransactionAmount(operation.transaction); + transaction && getAssetById(transaction.args.asset, chainsService.getChainById(operation.chainId)?.assets); + const amount = transaction && getTransactionAmount(transaction); return ( <> - + {asset && amount && (
diff --git a/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx b/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx index f074aba2e2..14402454ba 100644 --- a/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx +++ b/src/renderer/features/transfer-operation-details/components/XcmTransferOperationTitle.tsx @@ -3,6 +3,7 @@ import { type FlexibleMultisigTransactionDS, type MultisigTransactionDS } from ' import { getAssetById } from '@/shared/lib/utils'; import { AssetBalance } from '@/entities/asset'; import { XcmChains } from '@/entities/chain'; +import { getTransactionFromMultisigTx } from '@/entities/multisig'; import { TransactionTitle, getTransactionAmount } from '@/entities/transaction'; type Props = { @@ -10,15 +11,16 @@ type Props = { }; export const XcmTransferOperationTitle = ({ operation }: Props) => { - const assetId = operation.transaction?.args.assetId || operation.transaction?.args.asset; - const chainId = operation.transaction?.args.destinationChain || operation.chainId; - const asset = getAssetById(assetId, chainsService.getChainById(chainId)?.assets); + const transaction = getTransactionFromMultisigTx(operation); - const amount = operation.transaction && getTransactionAmount(operation.transaction); + const assetId = transaction?.args.assetId || transaction?.args.asset; + const asset = getAssetById(assetId, chainsService.getChainById(operation.chainId)?.assets); + + const amount = transaction && getTransactionAmount(transaction); return ( <> - + {asset && amount && (
@@ -26,11 +28,7 @@ export const XcmTransferOperationTitle = ({ operation }: Props) => {
)} - + ); }; diff --git a/src/renderer/shared/api/xcm/__tests__/mock/xcmData.ts b/src/renderer/shared/api/xcm/__tests__/mock/xcmData.ts index 4801e07e90..2c5bfa42f3 100644 --- a/src/renderer/shared/api/xcm/__tests__/mock/xcmData.ts +++ b/src/renderer/shared/api/xcm/__tests__/mock/xcmData.ts @@ -314,6 +314,69 @@ export const XCMPALLET_TRANSFER_PAH_MYTH = { }, }; +export const XCMPALLET_TRANSFER_PAH_MOONBEAM = { + dest: { + V4: { + interior: { + X1: [ + { + Parachain: '2,004', + }, + ], + }, + parents: 1, + }, + }, + beneficiary: { + V4: { + interior: { + X1: [ + { + AccountKey20: { + key: '0xb32b41625e14e55757a5d0cfcdd9768a1695c5f3', + network: null, + }, + }, + ], + }, + parents: 0, + }, + }, + assets: { + V4: [ + { + fun: { + Fungible: '5340000000000000', + }, + id: { + interior: { + X2: [ + { + PalletInstance: 50, + }, + { + GeneralIndex: '23', + }, + ], + }, + parents: 0, + }, + }, + { + fun: { + Fungible: '156796325', + }, + id: { + interior: { + Here: 'NULL', + }, + parents: 1, + }, + }, + ], + }, +}; + export const XTOKENS_ACA_DOT = { asset: { V2: { diff --git a/src/renderer/shared/api/xcm/__tests__/xcm-service.test.ts b/src/renderer/shared/api/xcm/__tests__/xcm-service.test.ts index 3ab4edc71e..936bfa17f7 100644 --- a/src/renderer/shared/api/xcm/__tests__/xcm-service.test.ts +++ b/src/renderer/shared/api/xcm/__tests__/xcm-service.test.ts @@ -4,6 +4,7 @@ import { CONFIG, XCMPALLET_TRANSFER_HUB_ASTAR, XCMPALLET_TRANSFER_KSM_BIFROST, + XCMPALLET_TRANSFER_PAH_MOONBEAM, XCMPALLET_TRANSFER_PAH_MYTH, XTOKENS_ACA_DOT, XTOKENS_ACA_PARALLEL, @@ -40,6 +41,21 @@ describe('shared/api/xcm/service/xcm-service', () => { }); }); + test('should parse xcmPallet parachain > eth parachain 2', () => { + const result = xcmService.parseXcmPalletExtrinsic(XCMPALLET_TRANSFER_PAH_MOONBEAM); + + expect(result).toEqual({ + isRelayToken: false, + amount: '5340000000000000', + assetGeneralIndex: '23', + assetParachain: 0, + destAccountId: '0xb32b41625e14e55757a5d0cfcdd9768a1695c5f3', + destParachain: 2004, + toRelayChain: false, + type: 'xcmPallet', + }); + }); + test('should parse xcmPallet parachain > parachain', () => { const result = xcmService.parseXcmPalletExtrinsic(XCMPALLET_TRANSFER_HUB_ASTAR); diff --git a/src/renderer/shared/api/xcm/lib/xcm-utils.ts b/src/renderer/shared/api/xcm/lib/xcm-utils.ts index bb1641bdc9..5f5d0c2668 100644 --- a/src/renderer/shared/api/xcm/lib/xcm-utils.ts +++ b/src/renderer/shared/api/xcm/lib/xcm-utils.ts @@ -246,7 +246,9 @@ function getSiblingLocation(version: string, parachainId: number, accountId?: Ac function getJunctionCols(interior: Record, path: string): T { if (path === 'X1') { - return get(interior, path) as T; + const result = get(interior, path) as T; + + return Array.isArray(result) ? result[0] : result; } return Object.values(get(interior, path)).reduce((acc, item) => { diff --git a/src/renderer/shared/api/xcm/service/xcmService.ts b/src/renderer/shared/api/xcm/service/xcmService.ts index 294d69f249..d345b52f0c 100644 --- a/src/renderer/shared/api/xcm/service/xcmService.ts +++ b/src/renderer/shared/api/xcm/service/xcmService.ts @@ -218,7 +218,8 @@ type XTokensPayload = ParsedPayload & { function parseXcmPalletExtrinsic(args: Omit): XcmPalletPayload { const xcmVersion = Object.keys(args.dest as NonNullable)[0]; - const assetInterior = get(args.assets, `${xcmVersion}[0].id.Concrete.interior`) as unknown as NonNullable; + const assetInterior = (get(args.assets, `${xcmVersion}[0].id.Concrete.interior`) || + get(args.assets, `${xcmVersion}[0].id.interior`)) as unknown as NonNullable; const destInterior = get(args.dest, `${xcmVersion}.interior`) as unknown as NonNullable; const beneficiaryInterior = get(args.beneficiary, `${xcmVersion}.interior`) as unknown as NonNullable; @@ -234,12 +235,18 @@ function parseXcmPalletExtrinsic(args: Omit( + beneficiaryInterior, + beneficiaryJunction, + ); + + parsedPayload.destAccountId = (get(beneficiaryCols, 'AccountId32.id') || + get(beneficiaryCols, 'AccountKey20.key')) as unknown as string; const destJunction = Object.keys(destInterior)[0]; - parsedPayload.destParachain = Number(xcmUtils.toRawString(get(destInterior, `${destJunction}.Parachain`))); + const destParachain = xcmUtils.getJunctionCols<{ Parachain: string }>(destInterior, destJunction); + parsedPayload.destParachain = Number(xcmUtils.toRawString(get(destParachain, 'Parachain'))); if (!parsedPayload.isRelayToken && assetInterior) { const assetJunction = Object.keys(assetInterior)[0]; @@ -280,10 +287,8 @@ function parseXTokensExtrinsic(args: Omit(destInterior, destJunction); + parsedPayload.destAccountId = (get(cols, 'AccountId32.id') || get(cols, 'AccountKey20.key')) as unknown as string; } else { const cols = xcmUtils.getJunctionCols<{ Parachain?: number }>(destInterior, destJunction); if (cols.Parachain) { From 970fc8080c68a2c88202760c07769ea4e45a33c3 Mon Sep 17 00:00:00 2001 From: asmadek Date: Tue, 4 Feb 2025 11:12:40 +0500 Subject: [PATCH 3/4] fix: transaction confirm on multisig --- .../Operations/components/ActionSteps/Confirmation.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/renderer/pages/Operations/components/ActionSteps/Confirmation.tsx b/src/renderer/pages/Operations/components/ActionSteps/Confirmation.tsx index 08bd0143ab..f85b1a5180 100644 --- a/src/renderer/pages/Operations/components/ActionSteps/Confirmation.tsx +++ b/src/renderer/pages/Operations/components/ActionSteps/Confirmation.tsx @@ -52,9 +52,8 @@ export const Confirmation = ({ api, tx, account, chain, signAccount, feeTx, onSi }); const xcmConfig = useUnit(xcmTransferModel.$config); - const asset = getAssetById(tx.transaction?.args.assetId, chain.assets) || chain.assets[0]; - const transaction = getTransactionFromMultisigTx(tx); + const asset = getAssetById(transaction?.args.assetId, chain.assets) || chain.assets[0]; const xcmApi = useStoreMap({ store: networkModel.$apis, @@ -75,9 +74,9 @@ export const Confirmation = ({ api, tx, account, chain, signAccount, feeTx, onSi return (
- + - {tx.transaction && } + {transaction && }
From 8ac5b0a2fe94bf2b85af22c462caec7d01cde1b7 Mon Sep 17 00:00:00 2001 From: asmadek Date: Tue, 4 Feb 2025 11:22:50 +0500 Subject: [PATCH 4/4] fix: details for mst confirm --- .../pages/Operations/components/Details.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/renderer/pages/Operations/components/Details.tsx b/src/renderer/pages/Operations/components/Details.tsx index a895991909..857c63b816 100644 --- a/src/renderer/pages/Operations/components/Details.tsx +++ b/src/renderer/pages/Operations/components/Details.tsx @@ -123,19 +123,19 @@ export const Details = ({ api, tx, account, chain, signatory }: Props) => { }, [validatorsMap]); const startStakingValidators: Address[] = - (tx.transaction?.type === 'batchAll' && - tx.transaction.args.transactions.find((tx: Transaction) => tx.type === 'nominate')?.args?.targets) || + (transaction?.type === 'batchAll' && + transaction.args.transactions.find((tx: Transaction) => tx.type === 'nominate')?.args?.targets) || []; const selectedValidators: Validator[] = allValidators.filter((v) => (transaction?.args.targets || startStakingValidators).includes(v.address)) || []; const proxied = useMemo((): { wallet: Wallet; account: AccountType } | undefined => { - if (!tx.transaction || !isProxyTransaction(tx.transaction)) { + if (!transaction || !isProxyTransaction(transaction)) { return undefined; } - const proxiedAccountId = toAccountId(tx.transaction.args.real); + const proxiedAccountId = toAccountId(transaction.args.real); const { wallet, account } = wallets.reduce<{ wallet?: Wallet; account?: AccountType }>( (acc, wallet) => { if (acc.wallet) { @@ -156,11 +156,11 @@ export const Details = ({ api, tx, account, chain, signatory }: Props) => { return { wallet, account }; }, [tx, wallets]); - const hasSender = isXcmTransaction(tx.transaction) || isTransferTransaction(tx.transaction); + const hasSender = isXcmTransaction(transaction) || isTransferTransaction(transaction); const isDividerVisible = - (isXcmTransaction(tx.transaction) && transaction?.args.destinationChain) || - isManageProxyTransaction(tx.transaction) || + (isXcmTransaction(transaction) && transaction?.args.destinationChain) || + isManageProxyTransaction(transaction) || destination || selectedValidators.length !== 0; @@ -267,7 +267,7 @@ export const Details = ({ api, tx, account, chain, signatory }: Props) => { )} - {isXcmTransaction(tx.transaction) && destinationChain && ( + {isXcmTransaction(transaction) && destinationChain && (