Skip to content

Commit

Permalink
fix(PRO-156): bugs 5, 8
Browse files Browse the repository at this point in the history
  • Loading branch information
siandreev committed Dec 25, 2024
1 parent 36c100c commit 3f7cf35
Show file tree
Hide file tree
Showing 18 changed files with 173 additions and 147 deletions.
3 changes: 2 additions & 1 deletion packages/core/src/service/ton-blockchain/sender/ISender.ts
Original file line number Diff line number Diff line change
@@ -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<Cell>;

estimate(outgoing: WalletOutgoingMessage): Promise<Estimation>;
estimate(outgoing: WalletOutgoingMessage): Promise<Estimation<TonAsset>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends LedgerTransaction | LedgerTransaction[]>(
tx: T
): Promise<T extends LedgerTransaction ? Cell : Cell[]> {
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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() {
Expand All @@ -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)]
});
Expand All @@ -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)]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
EXTERNAL_SENDER_CHOICE,
SenderChoice,
SenderChoiceUserAvailable,
TWO_FA_SENDER_CHOICE,
useGetEstimationSender,
useGetSender,
useTonConnectAvailableSendersChoices
Expand Down Expand Up @@ -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]);

Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<number>();
Expand Down
7 changes: 0 additions & 7 deletions packages/uikit/src/components/transfer/nft/ConfirmNftView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import {
BATTERY_SENDER_CHOICE,
EXTERNAL_SENDER_CHOICE,
SenderTypeUserAvailable,
TWO_FA_SENDER_CHOICE,
useAvailableSendersChoices,
useGetEstimationSender,
useGetSender
Expand Down Expand Up @@ -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]);

Expand Down Expand Up @@ -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}`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,15 @@
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';
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 (
<NotificationStyled isOpen={isOpen} handleClose={onClose}>
{() =>
!!authLink && (
<ConfirmView2FATelegramContent
validUntilSeconds={validUntilSeconds}
onClose={onClose}
openTgLink={authLink}
creationTimeSeconds={creationTimeSeconds}
/>
)
}
</NotificationStyled>
);
};

const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
Expand Down
8 changes: 2 additions & 6 deletions packages/uikit/src/hooks/blockchain/nft/useEstimateNftLink.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
8 changes: 2 additions & 6 deletions packages/uikit/src/hooks/blockchain/nft/useLinkNft.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -19,9 +17,7 @@ export const useLinkNft = (args: { nftAddress: string; linkToAddress: string })
return useMutation<boolean, Error>(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)
);
Expand Down
8 changes: 2 additions & 6 deletions packages/uikit/src/hooks/blockchain/nft/useRenewNft.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -19,9 +17,7 @@ export const useRenewNft = (args: { nftAddress: string }) => {
return useMutation<boolean, Error>(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)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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();

Expand Down
Loading

0 comments on commit 3f7cf35

Please sign in to comment.