diff --git a/packages/core/src/service/ton-blockchain/sender/ISender.ts b/packages/core/src/service/ton-blockchain/sender/ISender.ts index a8b29f239..b578c3bbe 100644 --- a/packages/core/src/service/ton-blockchain/sender/ISender.ts +++ b/packages/core/src/service/ton-blockchain/sender/ISender.ts @@ -1,11 +1,12 @@ import { WalletOutgoingMessage } from '../encoder/types'; import { Cell } from '@ton/core'; import { Estimation } from '../../../entries/send'; +import { TonAsset } from '../../../entries/crypto/asset/ton-asset'; export interface ISender { excessAddress: string; send(outgoing: WalletOutgoingMessage): Promise; - estimate(outgoing: WalletOutgoingMessage): Promise; + estimate(outgoing: WalletOutgoingMessage): Promise>; } diff --git a/packages/core/src/service/ton-blockchain/sender/ledger-message-sender.ts b/packages/core/src/service/ton-blockchain/sender/ledger-message-sender.ts index 04e733f0e..a4bd824e0 100644 --- a/packages/core/src/service/ton-blockchain/sender/ledger-message-sender.ts +++ b/packages/core/src/service/ton-blockchain/sender/ledger-message-sender.ts @@ -22,21 +22,26 @@ import { JettonEncoder } from '../encoder/jetton-encoder'; import { NFTEncoder } from '../encoder/nft-encoder'; import { TonConnectTransactionPayload } from '../../../entries/tonConnect'; import { LedgerError } from '../../../errors/LedgerError'; -import { MessagePayloadParam, serializePayload } from '../encoder/types'; +import { MessagePayloadParam, serializePayload, WalletOutgoingMessage } from '../encoder/types'; import { TonPayloadFormat } from '@ton-community/ton-ledger/dist/TonTransport'; import { TON_ASSET } from '../../../entries/crypto/asset/constants'; import { TonEstimation } from '../../../entries/send'; import { LedgerTransaction } from '../../ledger/connector'; import { WalletMessageSender } from './wallet-message-sender'; import { TonConnectEncoder } from '../encoder/ton-connect-encoder'; +import { ISender } from './ISender'; -export class LedgerMessageSender { +export class LedgerMessageSender implements ISender { constructor( private readonly api: APIConfig, private readonly wallet: TonWalletStandard, private readonly signer: LedgerSigner ) {} + public get excessAddress() { + return this.wallet.rawAddress; + } + private async sign( tx: T ): Promise { @@ -48,6 +53,51 @@ export class LedgerMessageSender { } } + private async toExternals(outgoing: WalletOutgoingMessage) { + const { timestamp, seqno, contract } = await this.getTransferParameters(); + + const transferCells = await this.sign( + outgoing.messages.map((message, index) => { + if (message.info.type !== 'internal') { + throw new Error('Only internal messages are supported by Ledger'); + } + + return { + to: message.info.dest, + bounce: message.info.bounce, + amount: message.info.value.coins, + seqno: seqno + index, + timeout: getTTL(timestamp + index * 60), + sendMode: outgoing.sendMode, + payload: message.body + ? { + type: 'unsafe' as const, + message: message.body + } + : undefined, + stateInit: message.init ?? undefined + }; + }) + ); + + return transferCells.map((cell, index) => externalMessage(contract, seqno + index, cell)); + } + + public async send(outgoing: WalletOutgoingMessage) { + const externals = await this.toExternals(outgoing); + + await new BlockchainApi(this.api.tonApiV2).sendBlockchainMessage({ + sendBlockchainMessageRequest: { + batch: externals.map(message => message.toBoc().toString('base64')) + } + }); + return externals[0]; + } + + public async estimate(outgoing: WalletOutgoingMessage) { + return new WalletMessageSender(this.api, this.wallet, estimationSigner).estimate(outgoing); + } + tonRawTransfer = async ({ to, value, diff --git a/packages/core/src/service/ton-blockchain/sender/multisig-create-order-sender.ts b/packages/core/src/service/ton-blockchain/sender/multisig-create-order-sender.ts index 7794ccad7..0cf9a006f 100644 --- a/packages/core/src/service/ton-blockchain/sender/multisig-create-order-sender.ts +++ b/packages/core/src/service/ton-blockchain/sender/multisig-create-order-sender.ts @@ -1,14 +1,11 @@ import { APIConfig } from '../../../entries/apis'; import { assertBalanceEnough, getServerTime } from '../utils'; -import { Signer } from '../../../entries/signer'; import { WalletOutgoingMessage } from '../encoder/types'; import { type Multisig } from '../../../tonApiV2'; import { TonWalletStandard } from '../../../entries/wallet'; import { ISender } from './ISender'; import { MultisigEncoder } from '../encoder/multisig-encoder/multisig-encoder'; -import { WalletMessageSender } from './wallet-message-sender'; import BigNumber from 'bignumber.js'; -import { LedgerMessageSender } from './ledger-message-sender'; import { fromNano, internal, SendMode } from '@ton/core'; import { TON_ASSET } from '../../../entries/crypto/asset/constants'; @@ -18,7 +15,7 @@ export class MultisigCreateOrderSender implements ISender { private readonly multisig: Multisig, private readonly ttlSeconds: number, private readonly hostWallet: TonWalletStandard, - private readonly signer: Signer + private readonly hostWalletSender: ISender ) {} public get excessAddress() { @@ -29,18 +26,7 @@ export class MultisigCreateOrderSender implements ISender { await this.checkTransactionPossibility(); const wrappedMessage = await this.wrapMessage(outgoing); - if (this.signer.type === 'ledger') { - const sender = new LedgerMessageSender(this.api, this.hostWallet, this.signer); - return ( - await sender.tonRawTransfer({ - ...wrappedMessage, - sendMode: SendMode.IGNORE_ERRORS - }) - ).send(); - } - - const sender = new WalletMessageSender(this.api, this.hostWallet, this.signer); - return sender.send({ + return this.hostWalletSender.send({ sendMode: SendMode.IGNORE_ERRORS, messages: [internal(wrappedMessage)] }); @@ -49,18 +35,7 @@ export class MultisigCreateOrderSender implements ISender { public async estimate(outgoing: WalletOutgoingMessage) { const wrappedMessage = await this.wrapMessage(outgoing); - if (this.signer.type === 'ledger') { - const sender = new LedgerMessageSender(this.api, this.hostWallet, this.signer); - return ( - await sender.tonRawTransfer({ - ...wrappedMessage, - sendMode: SendMode.IGNORE_ERRORS - }) - ).estimate(); - } - - const sender = new WalletMessageSender(this.api, this.hostWallet, this.signer); - return sender.estimate({ + return this.hostWalletSender.estimate({ sendMode: SendMode.IGNORE_ERRORS, messages: [internal(wrappedMessage)] }); diff --git a/packages/uikit/src/components/connect/TonTransactionNotification.tsx b/packages/uikit/src/components/connect/TonTransactionNotification.tsx index b345c5757..10500530c 100644 --- a/packages/uikit/src/components/connect/TonTransactionNotification.tsx +++ b/packages/uikit/src/components/connect/TonTransactionNotification.tsx @@ -32,7 +32,6 @@ import { EXTERNAL_SENDER_CHOICE, SenderChoice, SenderChoiceUserAvailable, - TWO_FA_SENDER_CHOICE, useGetEstimationSender, useGetSender, useTonConnectAvailableSendersChoices @@ -189,10 +188,6 @@ const ConnectContent: FC<{ return EXTERNAL_SENDER_CHOICE; } - if (selectedSenderType === TWO_FA_SENDER_CHOICE.type) { - return TWO_FA_SENDER_CHOICE; - } - throw new Error('Unexpected sender choice'); }, [selectedSenderType]); diff --git a/packages/uikit/src/components/modals/ConfirmTwoFANotificationControlled.tsx b/packages/uikit/src/components/modals/ConfirmTwoFANotificationControlled.tsx index a73850534..99dff605a 100644 --- a/packages/uikit/src/components/modals/ConfirmTwoFANotificationControlled.tsx +++ b/packages/uikit/src/components/modals/ConfirmTwoFANotificationControlled.tsx @@ -1,6 +1,6 @@ import { createModalControl } from './createModalControl'; import React, { FC, useEffect, useState } from 'react'; -import { useTwoFAServiceConfig, useTwoFAWalletConfig } from '../../state/two-fa'; +import { useTwoFAServiceConfig, useTwoFAWalletConfigMayBeOfMultisigHost } from '../../state/two-fa'; import styled from 'styled-components'; import { Notification } from '../Notification'; import { ConfirmView2FATelegramContent } from '../transfer/nft/ConfirmView2FATelegram'; @@ -27,7 +27,7 @@ export const ConfirmTwoFANotificationControlled = () => { const Content: FC<{ isOpen: boolean; onClose: () => void }> = ({ isOpen, onClose }) => { const { confirmMessageTGTtlSeconds } = useTwoFAServiceConfig(); - const { data: walletConfig } = useTwoFAWalletConfig(); + const { data: walletConfig } = useTwoFAWalletConfigMayBeOfMultisigHost(); const authLink = walletConfig && 'botUrl' in walletConfig ? walletConfig.botUrl : undefined; const [creationTimeSeconds, setCreationTimeSeconds] = useState(); diff --git a/packages/uikit/src/components/transfer/nft/ConfirmNftView.tsx b/packages/uikit/src/components/transfer/nft/ConfirmNftView.tsx index b14b8fede..0de66945f 100644 --- a/packages/uikit/src/components/transfer/nft/ConfirmNftView.tsx +++ b/packages/uikit/src/components/transfer/nft/ConfirmNftView.tsx @@ -38,7 +38,6 @@ import { BATTERY_SENDER_CHOICE, EXTERNAL_SENDER_CHOICE, SenderTypeUserAvailable, - TWO_FA_SENDER_CHOICE, useAvailableSendersChoices, useGetEstimationSender, useGetSender @@ -82,10 +81,6 @@ const useNftTransferEstimation = ( return BATTERY_SENDER_CHOICE; } - if (selectedSenderType === 'two_fa') { - return TWO_FA_SENDER_CHOICE; - } - throw new Error(`Unsupported sender type for nft transfer ${selectedSenderType}`); }, [selectedSenderType, account]); @@ -166,8 +161,6 @@ const useSendNft = ( senderChoice = EXTERNAL_SENDER_CHOICE; } else if (options.selectedSenderType === 'battery') { senderChoice = BATTERY_SENDER_CHOICE; - } else if (options.selectedSenderType === 'two_fa') { - senderChoice = TWO_FA_SENDER_CHOICE; } else { throw new Error( `Unsupported sender type for nft transfer ${options.selectedSenderType}` diff --git a/packages/uikit/src/components/transfer/nft/ConfirmView2FATelegram.tsx b/packages/uikit/src/components/transfer/nft/ConfirmView2FATelegram.tsx index 2b2252555..9e49ea70e 100644 --- a/packages/uikit/src/components/transfer/nft/ConfirmView2FATelegram.tsx +++ b/packages/uikit/src/components/transfer/nft/ConfirmView2FATelegram.tsx @@ -1,4 +1,4 @@ -import { closeAllNotifications, Notification } from '../../Notification'; +import { closeAllNotifications } from '../../Notification'; import styled from 'styled-components'; import { FC, useEffect, useRef } from 'react'; import { useCountdown } from '../../../hooks/useCountDown'; @@ -6,46 +6,10 @@ import { Body2, Body2Class, Label2 } from '../../Text'; import { useTranslation } from '../../../hooks/translation'; import { Button } from '../../fields/Button'; import { TelegramIcon } from '../../Icon'; -import { useTwoFAServiceConfig, useTwoFAWalletConfig } from '../../../state/two-fa'; import { useAppSdk } from '../../../hooks/appSdk'; import { Link } from 'react-router-dom'; import { AppRoute, WalletSettingsRoute } from '../../../libs/routes'; -const NotificationStyled = styled(Notification)` - .dialog-header { - padding-bottom: 0; - } -`; - -export const ConfirmView2FATelegram: FC<{ - isOpen: boolean; - onClose: () => void; - creationDateMS: number; -}> = ({ isOpen, onClose, creationDateMS }) => { - const { confirmMessageTGTtlSeconds } = useTwoFAServiceConfig(); - const { data: walletConfig } = useTwoFAWalletConfig(); - const authLink = walletConfig && 'botUrl' in walletConfig ? walletConfig.botUrl : undefined; - - const creationTimeSeconds = Math.round(creationDateMS / 1000); - - const validUntilSeconds = creationTimeSeconds + confirmMessageTGTtlSeconds; - - return ( - - {() => - !!authLink && ( - - ) - } - - ); -}; - const ContentWrapper = styled.div` display: flex; flex-direction: column; diff --git a/packages/uikit/src/hooks/blockchain/nft/useEstimateNftLink.ts b/packages/uikit/src/hooks/blockchain/nft/useEstimateNftLink.ts index 0f5838107..b61a8743d 100644 --- a/packages/uikit/src/hooks/blockchain/nft/useEstimateNftLink.ts +++ b/packages/uikit/src/hooks/blockchain/nft/useEstimateNftLink.ts @@ -1,17 +1,13 @@ import { useQuery } from '@tanstack/react-query'; -import { EXTERNAL_SENDER_CHOICE, TWO_FA_SENDER_CHOICE, useGetEstimationSender } from '../useSender'; +import { EXTERNAL_SENDER_CHOICE, useGetEstimationSender } from '../useSender'; import { useTonRawTransactionService } from '../useBlockchainService'; import { NFTEncoder } from '@tonkeeper/core/dist/service/ton-blockchain/encoder/nft-encoder'; import { useActiveAccount } from '../../../state/wallet'; import { useToQueryKeyPart } from '../../useToQueryKeyPart'; import { TonEstimation } from '@tonkeeper/core/dist/entries/send'; -import { useTwoFAWalletConfig } from '../../../state/two-fa'; export const useEstimateNftLink = (args: { nftAddress: string; linkToAddress: string }) => { - const { data: twoFaConfig } = useTwoFAWalletConfig(); - const getSender = useGetEstimationSender( - twoFaConfig?.status === 'active' ? TWO_FA_SENDER_CHOICE : EXTERNAL_SENDER_CHOICE - ); + const getSender = useGetEstimationSender(EXTERNAL_SENDER_CHOICE); const getSenderKey = useToQueryKeyPart(getSender); const rawTransactionService = useTonRawTransactionService(); const activeAccount = useActiveAccount(); diff --git a/packages/uikit/src/hooks/blockchain/nft/useEstimateNftRenew.ts b/packages/uikit/src/hooks/blockchain/nft/useEstimateNftRenew.ts index bd8ac394c..c47e9df43 100644 --- a/packages/uikit/src/hooks/blockchain/nft/useEstimateNftRenew.ts +++ b/packages/uikit/src/hooks/blockchain/nft/useEstimateNftRenew.ts @@ -2,16 +2,12 @@ import { useTonRawTransactionService } from '../useBlockchainService'; import { useActiveAccount } from '../../../state/wallet'; import { useQuery } from '@tanstack/react-query'; import { NFTEncoder } from '@tonkeeper/core/dist/service/ton-blockchain/encoder/nft-encoder'; -import { EXTERNAL_SENDER_CHOICE, TWO_FA_SENDER_CHOICE, useGetEstimationSender } from '../useSender'; +import { EXTERNAL_SENDER_CHOICE, useGetEstimationSender } from '../useSender'; import { useToQueryKeyPart } from '../../useToQueryKeyPart'; import { TonEstimation } from '@tonkeeper/core/dist/entries/send'; -import { useTwoFAWalletConfig } from '../../../state/two-fa'; export const useEstimateNftRenew = (args: { nftAddress: string }) => { - const { data: twoFaConfig } = useTwoFAWalletConfig(); - const getSender = useGetEstimationSender( - twoFaConfig?.status === 'active' ? TWO_FA_SENDER_CHOICE : EXTERNAL_SENDER_CHOICE - ); + const getSender = useGetEstimationSender(EXTERNAL_SENDER_CHOICE); const getSenderKey = useToQueryKeyPart(getSender); const rawTransactionService = useTonRawTransactionService(); const activeAccount = useActiveAccount(); diff --git a/packages/uikit/src/hooks/blockchain/nft/useLinkNft.ts b/packages/uikit/src/hooks/blockchain/nft/useLinkNft.ts index 2dff60693..a7c3556b6 100644 --- a/packages/uikit/src/hooks/blockchain/nft/useLinkNft.ts +++ b/packages/uikit/src/hooks/blockchain/nft/useLinkNft.ts @@ -1,14 +1,12 @@ -import { EXTERNAL_SENDER_CHOICE, TWO_FA_SENDER_CHOICE, useGetSender } from '../useSender'; +import { EXTERNAL_SENDER_CHOICE, useGetSender } from '../useSender'; import { useTonRawTransactionService } from '../useBlockchainService'; import { useActiveAccount } from '../../../state/wallet'; import { useMutation } from '@tanstack/react-query'; import { NFTEncoder } from '@tonkeeper/core/dist/service/ton-blockchain/encoder/nft-encoder'; import { zeroFee } from '@tonkeeper/core/dist/service/ton-blockchain/utils'; import { useTransactionAnalytics } from '../../amplitude'; -import { useTwoFAWalletConfig } from '../../../state/two-fa'; export const useLinkNft = (args: { nftAddress: string; linkToAddress: string }) => { - const { data: twoFaConfig } = useTwoFAWalletConfig(); const getSender = useGetSender(); const rawTransactionService = useTonRawTransactionService(); const activeAccount = useActiveAccount(); @@ -19,9 +17,7 @@ export const useLinkNft = (args: { nftAddress: string; linkToAddress: string }) return useMutation(async () => { const nftEncoder = new NFTEncoder(walletAddress); await rawTransactionService.send( - await getSender( - twoFaConfig?.status === 'active' ? TWO_FA_SENDER_CHOICE : EXTERNAL_SENDER_CHOICE - ), + await getSender(EXTERNAL_SENDER_CHOICE), zeroFee, nftEncoder.encodeNftLink(args) ); diff --git a/packages/uikit/src/hooks/blockchain/nft/useRenewNft.ts b/packages/uikit/src/hooks/blockchain/nft/useRenewNft.ts index cc20c750c..3bb77441a 100644 --- a/packages/uikit/src/hooks/blockchain/nft/useRenewNft.ts +++ b/packages/uikit/src/hooks/blockchain/nft/useRenewNft.ts @@ -1,14 +1,12 @@ -import { EXTERNAL_SENDER_CHOICE, TWO_FA_SENDER_CHOICE, useGetSender } from '../useSender'; +import { EXTERNAL_SENDER_CHOICE, useGetSender } from '../useSender'; import { useTonRawTransactionService } from '../useBlockchainService'; import { useActiveAccount } from '../../../state/wallet'; import { useTransactionAnalytics } from '../../amplitude'; import { useMutation } from '@tanstack/react-query'; import { NFTEncoder } from '@tonkeeper/core/dist/service/ton-blockchain/encoder/nft-encoder'; import { zeroFee } from '@tonkeeper/core/dist/service/ton-blockchain/utils'; -import { useTwoFAWalletConfig } from '../../../state/two-fa'; export const useRenewNft = (args: { nftAddress: string }) => { - const { data: twoFaConfig } = useTwoFAWalletConfig(); const getSender = useGetSender(); const rawTransactionService = useTonRawTransactionService(); const activeAccount = useActiveAccount(); @@ -19,9 +17,7 @@ export const useRenewNft = (args: { nftAddress: string }) => { return useMutation(async () => { const nftEncoder = new NFTEncoder(walletAddress); await rawTransactionService.send( - await getSender( - twoFaConfig?.status === 'active' ? TWO_FA_SENDER_CHOICE : EXTERNAL_SENDER_CHOICE - ), + await getSender(EXTERNAL_SENDER_CHOICE), zeroFee, nftEncoder.encodeNftRenew(args) ); diff --git a/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFARemove.ts b/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFARemove.ts index 4be9c63f7..1a5d785b3 100644 --- a/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFARemove.ts +++ b/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFARemove.ts @@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useAnalyticsTrack } from '../../amplitude'; import { useActiveWallet, useInvalidateActiveWalletQueries } from '../../../state/wallet'; import { useNotifyErrorHandle, useToast } from '../../useNotification'; -import { TWO_FA_SENDER_CHOICE, useGetSender } from '../useSender'; +import { EXTERNAL_SENDER_CHOICE, useGetSender } from '../useSender'; import { useTwoFAWalletConfig } from '../../../state/two-fa'; import { isStandardTonWallet } from '@tonkeeper/core/dist/entries/wallet'; import { TwoFAMessageSender } from '@tonkeeper/core/dist/service/ton-blockchain/sender/two-fa-message-sender'; @@ -31,7 +31,11 @@ export function useSendTwoFARemove() { throw new Error('Cant remove two fa plugin using this wallet'); } - const sender = (await getSender(TWO_FA_SENDER_CHOICE)) as TwoFAMessageSender; + const sender = await getSender(EXTERNAL_SENDER_CHOICE); + + if (!(sender instanceof TwoFAMessageSender)) { + throw new Error('Unexpected sender'); + } await sender.sendRemoveExtension(); diff --git a/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFCancelRecovery.ts b/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFCancelRecovery.ts index 20cfca751..9aedf5497 100644 --- a/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFCancelRecovery.ts +++ b/packages/uikit/src/hooks/blockchain/two-fa/useSendTwoFCancelRecovery.ts @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useActiveWallet, useInvalidateActiveWalletQueries } from '../../../state/wallet'; import { useNotifyErrorHandle } from '../../useNotification'; -import { TWO_FA_SENDER_CHOICE, useGetSender } from '../useSender'; +import { EXTERNAL_SENDER_CHOICE, useGetSender } from '../useSender'; import { useTwoFAWalletConfig } from '../../../state/two-fa'; import { isStandardTonWallet } from '@tonkeeper/core/dist/entries/wallet'; import { TwoFAMessageSender } from '@tonkeeper/core/dist/service/ton-blockchain/sender/two-fa-message-sender'; @@ -30,7 +30,11 @@ export function useSendTwoFACancelRecovery() { throw new Error('Cant remove two fa plugin using this wallet'); } - const sender = (await getSender(TWO_FA_SENDER_CHOICE)) as TwoFAMessageSender; + const sender = await getSender(EXTERNAL_SENDER_CHOICE); + + if (!(sender instanceof TwoFAMessageSender)) { + throw new Error('Unexpected sender'); + } await sender.sendCancelRecovery(); diff --git a/packages/uikit/src/hooks/blockchain/useEstimateTransfer.ts b/packages/uikit/src/hooks/blockchain/useEstimateTransfer.ts index 00bbe9539..bb4cfeca7 100644 --- a/packages/uikit/src/hooks/blockchain/useEstimateTransfer.ts +++ b/packages/uikit/src/hooks/blockchain/useEstimateTransfer.ts @@ -9,7 +9,6 @@ import { BATTERY_SENDER_CHOICE, EXTERNAL_SENDER_CHOICE, SenderTypeUserAvailable, - TWO_FA_SENDER_CHOICE, useGetEstimationSender } from './useSender'; import { useTonAssetTransferService } from './useBlockchainService'; @@ -43,10 +42,6 @@ export function useEstimateTransfer({ return BATTERY_SENDER_CHOICE; } - if (senderType === 'two_fa') { - return TWO_FA_SENDER_CHOICE; - } - if (senderType === 'gasless') { if (!isTonAsset(amount.asset)) { throw new Error('Unexpected asset'); diff --git a/packages/uikit/src/hooks/blockchain/useSendTransfer.ts b/packages/uikit/src/hooks/blockchain/useSendTransfer.ts index fbb1b7262..85e38c861 100644 --- a/packages/uikit/src/hooks/blockchain/useSendTransfer.ts +++ b/packages/uikit/src/hooks/blockchain/useSendTransfer.ts @@ -10,7 +10,6 @@ import { BATTERY_SENDER_CHOICE, EXTERNAL_SENDER_CHOICE, SenderTypeUserAvailable, - TWO_FA_SENDER_CHOICE, useGetSender } from './useSender'; import { useTonAssetTransferService } from './useBlockchainService'; @@ -58,8 +57,6 @@ export function useSendTransfer({ type: 'gasless', asset: amount.asset } as const; - } else if (senderType === 'two_fa') { - senderChoice = TWO_FA_SENDER_CHOICE; } if (!senderChoice) { diff --git a/packages/uikit/src/hooks/blockchain/useSender.ts b/packages/uikit/src/hooks/blockchain/useSender.ts index f6e185460..11c038380 100644 --- a/packages/uikit/src/hooks/blockchain/useSender.ts +++ b/packages/uikit/src/hooks/blockchain/useSender.ts @@ -42,13 +42,17 @@ import { TonConnectTransactionService } from '@tonkeeper/core/dist/service/ton-b import { useAssets } from '../../state/home'; import { JettonEncoder } from '@tonkeeper/core/dist/service/ton-blockchain/encoder/jetton-encoder'; import { toNano } from '@ton/core'; -import { useTwoFAApi, useTwoFAServiceConfig, useTwoFAWalletConfig } from '../../state/two-fa'; +import { + useTwoFAWalletConfigMayBeOfMultisigHost, + useTwoFAApi, + useTwoFAServiceConfig, + useTwoFAWalletConfig +} from '../../state/two-fa'; import { TwoFAMessageSender } from '@tonkeeper/core/dist/service/ton-blockchain/sender/two-fa-message-sender'; import { useConfirmTwoFANotification } from '../../components/modals/ConfirmTwoFANotificationControlled'; export type SenderChoice = | { type: 'multisig'; ttlSeconds: number } - | { type: 'two_fa' } | { type: 'external' } | { type: 'battery' } | { type: 'gasless'; asset: TonAsset }; @@ -100,7 +104,7 @@ export const useAvailableSendersChoices = ( } if (twoFaConfig?.status === 'active') { - return [TWO_FA_SENDER_CHOICE]; + return [EXTERNAL_SENDER_CHOICE]; } let batteryAvailable = false; @@ -186,11 +190,7 @@ export const useTonConnectAvailableSendersChoices = (payload: TonConnectTransact twoFaConfig?.status ], async () => { - if (twoFaConfig?.status === 'active') { - return [TWO_FA_SENDER_CHOICE]; - } - - if (account.type === 'ledger') { + if (account.type === 'ledger' || twoFaConfig?.status === 'active') { return [EXTERNAL_SENDER_CHOICE]; } const choices: SenderChoiceUserAvailable[] = [EXTERNAL_SENDER_CHOICE]; @@ -234,7 +234,6 @@ export const useTonConnectAvailableSendersChoices = (payload: TonConnectTransact }; export const EXTERNAL_SENDER_CHOICE = { type: 'external' } as const satisfies SenderChoice; -export const TWO_FA_SENDER_CHOICE = { type: 'two_fa' } as const satisfies SenderChoice; export const BATTERY_SENDER_CHOICE = { type: 'battery' } as const satisfies SenderChoice; export const useGetEstimationSender = (senderChoice: SenderChoice = { type: 'external' }) => { @@ -248,7 +247,7 @@ export const useGetEstimationSender = (senderChoice: SenderChoice = { type: 'ext const accounts = useAccountsState(); const gaslessConfig = useGaslessConfig(); const twoFaApi = useTwoFAApi(); - const { data: twoFAConfig } = useTwoFAWalletConfig(); + const { data: twoFAConfig } = useTwoFAWalletConfigMayBeOfMultisigHost(); const wallet = activeAccount.activeTonWallet; @@ -275,8 +274,6 @@ export const useGetEstimationSender = (senderChoice: SenderChoice = { type: 'ext activeAccount as AccountTonMultisig ); - const signer = estimationSigner; - const multisigApi = new MultisigApi(api.tonApiV2); const multisig = await multisigApi.getMultisigAccount({ accountId: activeAccount.activeTonWallet.rawAddress @@ -285,12 +282,24 @@ export const useGetEstimationSender = (senderChoice: SenderChoice = { type: 'ext throw new Error('Multisig not found'); } + let hostWalletSender; + if (twoFAConfig?.status === 'active') { + hostWalletSender = new TwoFAMessageSender( + { tonApi: api, twoFaApi }, + signerWallet, + estimationSigner, + twoFAConfig.pluginAddress + ); + } else { + hostWalletSender = new WalletMessageSender(api, signerWallet, estimationSigner); + } + return new MultisigCreateOrderSender( api, multisig, senderChoice.ttlSeconds, signerWallet, - signer + hostWalletSender ); } @@ -305,11 +314,7 @@ export const useGetEstimationSender = (senderChoice: SenderChoice = { type: 'ext return new WalletMessageSender(api, wallet, estimationSigner); } - if (senderChoice.type === 'two_fa') { - if (twoFAConfig?.status !== 'active') { - throw new Error('2FA is not active'); - } - + if (twoFAConfig?.status === 'active' || twoFAConfig?.status === 'disabling') { return new TwoFAMessageSender( { tonApi: api, twoFaApi }, wallet, @@ -396,7 +401,8 @@ export const useGetSender = () => { const accounts = useAccountsState(); const gaslessConfig = useGaslessConfig(); const twoFaApi = useTwoFAApi(); - const { data: twoFAConfig } = useTwoFAWalletConfig(); + + const { data: twoFAConfig } = useTwoFAWalletConfigMayBeOfMultisigHost(); const { onOpen: openTwoFaConfirmTelegram, onClose: closeTwoFaConfirmTelegram } = useConfirmTwoFANotification(); const twoFAServiceConfig = useTwoFAServiceConfig(); @@ -432,12 +438,35 @@ export const useGetSender = () => { throw new Error('Multisig not found'); } + let hostWalletSender; + + if (signer.type === 'ledger') { + hostWalletSender = new LedgerMessageSender(api, signerWallet, signer); + } else if (twoFAConfig?.status === 'active') { + hostWalletSender = new TwoFAMessageSender( + { tonApi: api, twoFaApi }, + signerWallet, + signer, + twoFAConfig.pluginAddress, + { + openConfirmModal: () => { + openTwoFaConfirmTelegram(); + return closeTwoFaConfirmTelegram; + }, + confirmMessageTGTtlSeconds: + twoFAServiceConfig.confirmMessageTGTtlSeconds + } + ); + } else { + hostWalletSender = new WalletMessageSender(api, signerWallet, signer); + } + return new MultisigCreateOrderSender( api, multisig, senderChoice.ttlSeconds, signerWallet, - signer + hostWalletSender ); } @@ -455,10 +484,25 @@ export const useGetSender = () => { ); const signer = await getSigner(signerAccount.id, signerWallet.id); - if (signer.type === 'cell') { - return new WalletMessageSender(api, signerWallet, signer); - } else { + if (signer.type === 'ledger') { return new LedgerMessageSender(api, signerWallet, signer); + } else if (twoFAConfig?.status === 'active') { + return new TwoFAMessageSender( + { tonApi: api, twoFaApi }, + signerWallet, + signer, + twoFAConfig.pluginAddress, + { + openConfirmModal: () => { + openTwoFaConfirmTelegram(); + return closeTwoFaConfirmTelegram; + }, + confirmMessageTGTtlSeconds: + twoFAServiceConfig.confirmMessageTGTtlSeconds + } + ); + } else { + return new WalletMessageSender(api, signerWallet, signer); } } @@ -479,11 +523,7 @@ export const useGetSender = () => { return new LedgerMessageSender(api, wallet, signer); } - if (senderChoice.type === 'two_fa') { - if (twoFAConfig?.status !== 'active' && twoFAConfig?.status !== 'disabling') { - throw new Error('2FA is not active'); - } - + if (twoFAConfig?.status === 'active' || twoFAConfig?.status === 'disabling') { return new TwoFAMessageSender( { tonApi: api, twoFaApi }, wallet, diff --git a/packages/uikit/src/state/multisig.ts b/packages/uikit/src/state/multisig.ts index b0bdaf6dd..e0e42f3fd 100644 --- a/packages/uikit/src/state/multisig.ts +++ b/packages/uikit/src/state/multisig.ts @@ -1,6 +1,5 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { anyOfKeysParts, QueryKey } from '../libs/queryKey'; -import { useAppContext } from '../hooks/appContext'; import { AccountsApi, BlockchainApi, diff --git a/packages/uikit/src/state/two-fa.ts b/packages/uikit/src/state/two-fa.ts index f362c296c..8ca84b3b2 100644 --- a/packages/uikit/src/state/two-fa.ts +++ b/packages/uikit/src/state/two-fa.ts @@ -19,6 +19,7 @@ import { assertUnreachable } from '@tonkeeper/core/dist/utils/types'; import { WalletId } from '@tonkeeper/core/dist/entries/wallet'; import { useToast } from '../hooks/useNotification'; import { useTranslation } from '../hooks/translation'; +import { getMultisigSignerInfo } from './multisig'; export type TwoFATgBotBoundingWalletConfig = { status: 'tg-bot-bounding'; @@ -100,6 +101,30 @@ export const useTwoFAServiceConfig = () => { }, [config]); }; +export const useTwoFAWalletConfigMayBeOfMultisigHost = () => { + const accounts = useAccountsState(); + const activeAccount = useActiveAccount(); + let multisigSignerInfo; + try { + if (activeAccount.type !== 'ton-multisig') { + multisigSignerInfo = null; + } else { + multisigSignerInfo = getMultisigSignerInfo(accounts, activeAccount); + } + } catch (e) { + multisigSignerInfo = null; + } + + return useTwoFAWalletConfig( + multisigSignerInfo + ? { + account: multisigSignerInfo.signerAccount, + walletId: multisigSignerInfo.signerWallet.id + } + : undefined + ); +}; + export const useTwoFAWalletConfig = (options?: { account?: Account; walletId?: WalletId }) => { const sdk = useAppSdk(); const activeAccount = useActiveAccount();