diff --git a/packages/@core-js/src/utils/tonProof.ts b/packages/@core-js/src/utils/tonProof.ts index 02869087d..43f2b0b1f 100644 --- a/packages/@core-js/src/utils/tonProof.ts +++ b/packages/@core-js/src/utils/tonProof.ts @@ -4,6 +4,7 @@ import nacl from 'tweetnacl'; import naclUtils from 'tweetnacl-util'; const { createHash } = require('react-native-crypto'); import { Address } from '../formatters/Address'; +import { getRawTimeFromLiteserverSafely } from '@tonkeeper/shared/utils/blockchain'; export interface TonProofArgs { address: string; @@ -22,7 +23,7 @@ export async function createTonProof({ }: TonProofArgs) { try { const address = Address.parse(_addr).toRaw(); - const timestamp = Math.floor(Date.now() / 1000); + const timestamp = await getRawTimeFromLiteserverSafely(); const timestampBuffer = new Int64LE(timestamp).toBuffer(); const domainBuffer = Buffer.from(domain); diff --git a/packages/mobile/src/core/TonConnect/TonConnectModal.tsx b/packages/mobile/src/core/TonConnect/TonConnectModal.tsx index 4b1b3d098..e3d371c29 100644 --- a/packages/mobile/src/core/TonConnect/TonConnectModal.tsx +++ b/packages/mobile/src/core/TonConnect/TonConnectModal.tsx @@ -174,7 +174,7 @@ export const TonConnectModal = (props: TonConnectModalProps) => { const { replyBuilder, requestPromise } = props; - const replyItems = replyBuilder.createReplyItems( + const replyItems = await replyBuilder.createReplyItems( address, privateKey, publicKey, diff --git a/packages/mobile/src/tonconnect/ConnectReplyBuilder.ts b/packages/mobile/src/tonconnect/ConnectReplyBuilder.ts index 3db9575d2..93bebf8e4 100644 --- a/packages/mobile/src/tonconnect/ConnectReplyBuilder.ts +++ b/packages/mobile/src/tonconnect/ConnectReplyBuilder.ts @@ -11,9 +11,9 @@ import nacl from 'tweetnacl'; import TonWeb from 'tonweb'; import { Buffer } from 'buffer'; import { getDomainFromURL } from '$utils'; -import { getTimeSec } from '$utils/getTimeSec'; import { Int64LE } from 'int64-buffer'; import { DAppManifest } from './models'; +import { getRawTimeFromLiteserverSafely } from '@tonkeeper/shared/utils/blockchain'; const { createHash } = require('react-native-crypto'); @@ -31,13 +31,13 @@ export class ConnectReplyBuilder { return getChainName() === 'mainnet' ? CHAIN.MAINNET : CHAIN.TESTNET; } - private createTonProofItem( + private async createTonProofItem( address: string, secretKey: Uint8Array, payload: string, - ): TonProofItemReply { + ): Promise { try { - const timestamp = getTimeSec(); + const timestamp = await getRawTimeFromLiteserverSafely(); const timestampBuffer = new Int64LE(timestamp).toBuffer(); const domain = getDomainFromURL(this.manifest.url); @@ -102,36 +102,41 @@ export class ConnectReplyBuilder { } } - createReplyItems( + async createReplyItems( addr: string, privateKey: Uint8Array, publicKey: Uint8Array, walletStateInit: string, isTestnet: boolean, - ): ConnectItemReply[] { + ): Promise { const address = new TonWeb.utils.Address(addr).toString(false, true, true); - const replyItems = this.request.items.map((requestItem): ConnectItemReply => { - switch (requestItem.name) { + const replyItems: ConnectItemReply[] = []; + for (const item of this.request.items) { + switch (item.name) { case 'ton_addr': - return { + replyItems.push({ name: 'ton_addr', address, network: isTestnet ? CHAIN.TESTNET : CHAIN.MAINNET, publicKey: Buffer.from(publicKey).toString('hex'), walletStateInit, - }; + }); + break; case 'ton_proof': - return this.createTonProofItem(address, privateKey, requestItem.payload); + replyItems.push( + await this.createTonProofItem(address, privateKey, item.payload), + ); + break; default: - return { - name: (requestItem as ConnectItem).name, + replyItems.push({ + name: (item as ConnectItem).name, error: { code: 400 }, - } as unknown as ConnectItemReply; + } as unknown as ConnectItemReply); } - }); + } return replyItems; } diff --git a/packages/mobile/src/utils/proof.ts b/packages/mobile/src/utils/proof.ts index 80e66e51f..91f0120cc 100644 --- a/packages/mobile/src/utils/proof.ts +++ b/packages/mobile/src/utils/proof.ts @@ -1,4 +1,3 @@ -import { getTimeSec } from '$utils/getTimeSec'; import { Int64LE } from 'int64-buffer'; import { Buffer } from 'buffer'; import nacl from 'tweetnacl'; @@ -7,6 +6,7 @@ const { createHash } = require('react-native-crypto'); import { ConnectApi, Configuration } from '@tonkeeper/core/src/legacy'; import { Address } from '@tonkeeper/core'; import { config } from '$config'; +import { getRawTimeFromLiteserverSafely } from '@tonkeeper/shared/utils/blockchain'; export interface TonProofArgs { address: string; @@ -37,7 +37,7 @@ export async function createTonProof({ if (!payload) { payload = (await connectApi.getTonConnectPayload()).payload; } - const timestamp = getTimeSec(); + const timestamp = await getRawTimeFromLiteserverSafely(); const timestampBuffer = new Int64LE(timestamp).toBuffer(); const domainBuffer = Buffer.from(domain); diff --git a/packages/shared/utils/blockchain.ts b/packages/shared/utils/blockchain.ts index 4513d3e77..3edb8942d 100644 --- a/packages/shared/utils/blockchain.ts +++ b/packages/shared/utils/blockchain.ts @@ -3,6 +3,7 @@ import { tk } from '@tonkeeper/mobile/src/wallet'; import { ContentType, ServiceStatus } from '@tonkeeper/core/src/TonAPI'; import { TransactionService } from '@tonkeeper/core'; import { t } from '../i18n'; +import { Alert } from 'react-native'; export class NetworkOverloadedError extends Error {} @@ -67,10 +68,20 @@ export async function emulateBoc( } } -export async function getTimeoutFromLiteserverSafely() { +export async function getRawTimeFromLiteserverSafely(): Promise { try { - return (await tk.wallet.tonapi.liteserver.getRawTime()).time + TransactionService.TTL; - } catch { - return TransactionService.getTimeout(); + const res = await tk.wallet.tonapi.liteserver.getRawTime({ + headers: { + 'Cache-Control': 'no-cache', + }, + cache: 'no-cache', + }); + return res.time; + } catch (e) { + return Math.floor(Date.now() / 1e3); } } + +export async function getTimeoutFromLiteserverSafely() { + return (await getRawTimeFromLiteserverSafely()) + TransactionService.TTL; +}