Skip to content

Commit

Permalink
v3.0.14
Browse files Browse the repository at this point in the history
  • Loading branch information
mytonwalletorg committed Sep 18, 2024
1 parent bfd0e99 commit 03670a6
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 41 deletions.
1 change: 1 addition & 0 deletions changelogs/3.0.14.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bug fixes and performance improvements
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mytonwallet",
"version": "3.0.13",
"version": "3.0.14",
"description": "The most feature-rich web wallet and browser extension for TON – with support of multi-accounts, tokens (jettons), NFT, TON DNS, TON Sites, TON Proxy, and TON Magic.",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -208,7 +208,7 @@
"pako": "^2.1.0",
"qr-code-styling": "github:troman29/qr-code-styling#c00d0",
"qrcode-generator": "^1.4.4",
"tonapi-sdk-js": "^1.0.10",
"tonapi-sdk-js": "^2.0.1",
"tonweb-mnemonic": "^1.0.1",
"tweetnacl": "^1.0.3",
"v8-compile-cache": "^2.4.0",
Expand Down
5 changes: 2 additions & 3 deletions public/static-sites/go/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ <h1>Open <span class="gradient-text">MyTonWallet</span></h1>
} = location;

const redirectTo = `${pathname.slice(1)}${search}`;
const protocol = redirectTo.startsWith('transfer') ? 'ton://' : 'mtw://';

document.getElementById('btn-sign-in').href = `${protocol}${redirectTo}`;
document.getElementById('btn-sign-in').href = `mtw://${redirectTo}`;

if (!search?.includes('no-redirect')) {
location.href = `${protocol}${redirectTo}`;
location.href = `mtw://${redirectTo}`;
history.replaceState({}, '', `${pathname}${search}${search ? '&' : '?'}no-redirect`);
}
</script>
Expand Down
2 changes: 1 addition & 1 deletion public/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.13
3.0.14
1 change: 1 addition & 0 deletions src/api/blockchains/ton/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Workchain } from '../../types';
export const TOKEN_TRANSFER_AMOUNT = 50000000n; // 0.05 TON
export const TINY_TOKEN_TRANSFER_AMOUNT = 18000000n; // 0.018 TON
export const TOKEN_TRANSFER_FORWARD_AMOUNT = 1n; // 0.000000001 TON
export const CLAIM_MINTLESS_AMOUNT = 20000000n; // 0.02 TON

export const NFT_TRANSFER_AMOUNT = 100000000n; // 0.1 TON
export const NFT_TRANSFER_FORWARD_AMOUNT = 1n; // 0.000000001 TON
Expand Down
82 changes: 72 additions & 10 deletions src/api/blockchains/ton/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { JettonBalance } from 'tonapi-sdk-js';
import { Address } from '@ton/core';
import { Address, Cell } from '@ton/core';

import type {
ApiBaseToken, ApiNetwork, ApiToken, ApiTokenSimple,
Expand All @@ -10,6 +10,7 @@ import {
DEFAULT_DECIMAL_PLACES, TINY_TOKENS, TON_SYMBOL, TONCOIN_SLUG,
} from '../../../config';
import { parseAccountId } from '../../../util/account';
import { fetchJson } from '../../../util/fetch';
import { logDebugError } from '../../../util/logs';
import { fixIpfsUrl } from '../../../util/metadata';
import { buildTokenSlug } from './util';
Expand All @@ -24,16 +25,18 @@ import {
getTonClient,
resolveTokenMinterAddress,
resolveTokenWalletAddress,
toBase64Address,
toBase64Address, toRawAddress,
} from './util/tonCore';
import { JettonWallet } from './contracts/JettonWallet';
import { fetchStoredAddress } from '../../common/accounts';
import {
CLAIM_MINTLESS_AMOUNT,
DEFAULT_DECIMALS,
TINY_TOKEN_TRANSFER_AMOUNT,
TOKEN_TRANSFER_AMOUNT,
TOKEN_TRANSFER_FORWARD_AMOUNT,
} from './constants';
import { isActiveSmartContract } from './wallet';

export type TokenBalanceParsed = {
slug: string;
Expand Down Expand Up @@ -63,12 +66,12 @@ export async function getAccountTokenBalances(accountId: string) {
}

export async function getTokenBalances(network: ApiNetwork, address: string) {
const balancesRaw: Array<JettonBalance> = await fetchJettonBalances(network, address);
const balancesRaw = await fetchJettonBalances(network, address);
return balancesRaw.map((balance) => parseTokenBalance(network, balance)).filter(Boolean);
}

export async function getAddressTokenBalances(address: string, network: ApiNetwork) {
const balancesRaw: Array<JettonBalance> = await fetchJettonBalances(network, address);
const balancesRaw = await fetchJettonBalances(network, address);
return balancesRaw.map((balance) => parseTokenBalance(network, balance)).filter(Boolean);
}

Expand All @@ -78,7 +81,9 @@ function parseTokenBalance(network: ApiNetwork, balanceRaw: JettonBalance): Toke
}

try {
const { balance, jetton, wallet_address: walletAddress } = balanceRaw;
const {
balance, jetton, wallet_address: walletAddress,
} = balanceRaw;
const minterAddress = toBase64Address(jetton.address, true, network);
const token = buildTokenByMetadata(minterAddress, jetton);

Expand Down Expand Up @@ -141,33 +146,88 @@ export async function buildTokenTransfer(
payload?: AnyPayload,
) {
const tokenWalletAddress = await resolveTokenWalletAddress(network, fromAddress, tokenAddress);
const realTokenAddress = await resolveTokenMinterAddress(network, tokenWalletAddress);
if (tokenAddress !== realTokenAddress) {
throw new Error('Invalid contract');
const tokenWallet = getTokenWallet(network, tokenWalletAddress);
const token = findTokenByMinter(tokenAddress)!;

let isTokenWalletDeployed = true;
let customPayload: string | undefined;
let stateInit: string | undefined;

const isMintlessToken = !!token.customPayloadApiUrl;
let isMintlessClaimed: boolean | undefined;
let mintlessTokenBalance: bigint | undefined;

if (isMintlessToken) {
isTokenWalletDeployed = !!(await isActiveSmartContract(network, tokenWalletAddress));
isMintlessClaimed = isTokenWalletDeployed && await checkMintlessTokenWalletIsClaimed(network, tokenWalletAddress);

if (!isMintlessClaimed) {
const data = await fetchMintlessTokenWalletData(token.customPayloadApiUrl!, fromAddress);

if (data) {
customPayload = data.custom_payload;
mintlessTokenBalance = BigInt(data.compressed_info.amount);

if (!isTokenWalletDeployed) {
stateInit = data.state_init;
}
}
}
}

const tokenWallet = getTokenWallet(network, tokenWalletAddress);
if (isTokenWalletDeployed) {
const realTokenAddress = await resolveTokenMinterAddress(network, tokenWalletAddress);
if (tokenAddress !== realTokenAddress) {
throw new Error('Invalid contract');
}
}

payload = buildTokenTransferBody({
tokenAmount: amount,
toAddress,
forwardAmount: TOKEN_TRANSFER_FORWARD_AMOUNT,
forwardPayload: payload,
responseAddress: fromAddress,
customPayload: customPayload ? Cell.fromBase64(customPayload) : undefined,
});

const toncoinAmount = TINY_TOKENS.has(tokenAddress)
let toncoinAmount = TINY_TOKENS.has(tokenAddress)
? TINY_TOKEN_TRANSFER_AMOUNT
: TOKEN_TRANSFER_AMOUNT;

if (mintlessTokenBalance && !isMintlessClaimed) {
toncoinAmount += CLAIM_MINTLESS_AMOUNT;
}

return {
tokenWallet,
amount: toncoinAmount,
toAddress: tokenWalletAddress,
payload,
stateInit: stateInit ? Cell.fromBase64(stateInit) : undefined,
mintlessTokenBalance,
isTokenWalletDeployed,
};
}

export async function checkMintlessTokenWalletIsClaimed(network: ApiNetwork, tokenWalletAddress: string) {
const res = await getTonClient(network)
.runMethod(Address.parse(tokenWalletAddress), 'is_claimed');
return res.stack.readBoolean();
}

async function fetchMintlessTokenWalletData(customPayloadApiUrl: string, address: string) {
const rawAddress = toRawAddress(address);

return (await fetchJson(`${customPayloadApiUrl}/wallet/${rawAddress}`).catch(() => undefined)) as {
custom_payload: string;
state_init: string;
compressed_info: {
amount: string;
};
} | undefined;
}

export function resolveTokenBySlug(slug: string) {
return knownTokens[slug]!;
}
Expand Down Expand Up @@ -217,6 +277,7 @@ function buildTokenByMetadata(address: string, metadata: JettonMetadata): ApiBas
image,
image_data: imageData,
decimals,
custom_payload_api_uri: customPayloadApiUrl,
} = metadata;

return {
Expand All @@ -226,5 +287,6 @@ function buildTokenByMetadata(address: string, metadata: JettonMetadata): ApiBas
decimals: decimals === undefined ? DEFAULT_DECIMALS : Number(decimals),
minterAddress: address,
image: (image && fixIpfsUrl(image)) || (imageData && fixBase64ImageData(imageData)) || undefined,
customPayloadApiUrl,
};
}
29 changes: 17 additions & 12 deletions src/api/blockchains/ton/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { OpenedContract } from '@ton/core';
import {
beginCell, Cell, external, internal, loadStateInit, SendMode, storeMessage,
} from '@ton/core';
Expand All @@ -15,7 +14,6 @@ import type {
ApiTransactionType,
ApiTxIdBySlug,
} from '../../types';
import type { JettonWallet } from './contracts/JettonWallet';
import type {
AnyPayload,
ApiCheckTransactionDraftResult,
Expand Down Expand Up @@ -200,23 +198,29 @@ export async function checkTransactionDraft(
data = commentToBytes(data);
}

let tokenBalance: bigint | undefined;
let tokenBalance = 0n;

if (!tokenAddress) {
if (data instanceof Uint8Array) {
data = shouldEncrypt ? packBytesAsSnakeForEncryptedData(data) : packBytesAsSnake(data);
}
} else {
const tokenAmount: bigint = amount;
let tokenWallet: OpenedContract<JettonWallet>;
({
tokenWallet,
amount,
toAddress,
payload: data,
} = await buildTokenTransfer(network, tokenAddress, address, toAddress, amount, data));
const tokenTransfer = await buildTokenTransfer(
network, tokenAddress, address, toAddress, amount, data,
);

({ amount, toAddress, payload: data } = tokenTransfer);
const { tokenWallet, isTokenWalletDeployed, mintlessTokenBalance } = tokenTransfer;

if (isTokenWalletDeployed) {
tokenBalance = await tokenWallet!.getJettonBalance();
}

if (mintlessTokenBalance) {
tokenBalance += mintlessTokenBalance;
}

tokenBalance = await tokenWallet!.getJettonBalance();
if (tokenBalance < tokenAmount!) {
return {
...result,
Expand Down Expand Up @@ -356,10 +360,10 @@ export async function submitTransfer(options: {
accountId,
password,
tokenAddress,
stateInit,
shouldEncrypt,
isBase64Data,
} = options;
let { stateInit } = options;

let { toAddress, amount, data } = options;

Expand Down Expand Up @@ -391,6 +395,7 @@ export async function submitTransfer(options: {
amount,
toAddress,
payload: data,
stateInit,
} = await buildTokenTransfer(network, tokenAddress, fromAddress, toAddress, amount, data));
}

Expand Down
2 changes: 2 additions & 0 deletions src/api/blockchains/ton/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface TokenTransferBodyParams {
responseAddress: string;
forwardAmount: bigint;
forwardPayload?: AnyPayload;
customPayload?: Cell;
}

export interface TonTransferParams {
Expand All @@ -41,6 +42,7 @@ export interface JettonMetadata {
image?: string;
image_data?: string;
uri?: string;
custom_payload_api_uri?: string;
}

export interface InitData {
Expand Down
11 changes: 10 additions & 1 deletion src/api/blockchains/ton/util/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const jettonOnChainMetadataSpec: {
image: 'ascii',
symbol: 'utf8',
decimals: 'utf8',
custom_payload_api_uri: 'ascii',
};

export async function fetchJettonMetadata(network: ApiNetwork, address: string) {
Expand Down Expand Up @@ -186,7 +187,15 @@ export async function parseJettonOnchainMetadata(slice: Slice): Promise<JettonMe

export async function fetchJettonOffchainMetadata(uri: string): Promise<JettonMetadata> {
const metadata = await fetchJsonMetadata(uri);
return pick(metadata, ['name', 'description', 'symbol', 'decimals', 'image', 'image_data']);
return pick(metadata, [
'name',
'description',
'symbol',
'decimals',
'image',
'image_data',
'custom_payload_api_uri',
]);
}

export async function parseWalletTransactionBody(
Expand Down
9 changes: 7 additions & 2 deletions src/api/blockchains/ton/util/tonCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ export function toRawAddress(address: Address | string) {

export function buildTokenTransferBody(params: TokenTransferBodyParams) {
const {
queryId, tokenAmount, toAddress, responseAddress, forwardAmount,
queryId,
tokenAmount,
toAddress,
responseAddress,
forwardAmount,
customPayload,
} = params;
let forwardPayload = params.forwardPayload;

Expand All @@ -175,7 +180,7 @@ export function buildTokenTransferBody(params: TokenTransferBodyParams) {
.storeCoins(tokenAmount)
.storeAddress(Address.parse(toAddress))
.storeAddress(Address.parse(responseAddress))
.storeBit(false)
.storeMaybeRef(customPayload)
.storeCoins(forwardAmount ?? 0n);

if (forwardPayload instanceof Uint8Array) {
Expand Down
4 changes: 3 additions & 1 deletion src/api/blockchains/ton/util/tonapiio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ function getApi(network: ApiNetwork) {
}

export async function fetchJettonBalances(network: ApiNetwork, account: string) {
return (await getApi(network).accounts.getAccountJettonsBalances(account)).balances;
return (await getApi(network).accounts.getAccountJettonsBalances(account, {
supported_extensions: ['custom_payload'],
})).balances;
}

export async function fetchNftItems(network: ApiNetwork, addresses: string[]) {
Expand Down
Loading

0 comments on commit 03670a6

Please sign in to comment.