Skip to content
2 changes: 1 addition & 1 deletion packages/extension-base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"@snowbridge/registry": "^0.2.0",
"@sora-substrate/type-definitions": "^1.17.7",
"@substrate/connect": "^0.8.9",
"@subwallet-monorepos/subwallet-services-sdk": "0.1.13",
"@subwallet-monorepos/subwallet-services-sdk": "0.1.13-beta.3",
"@subwallet/chain-list": "0.2.121",
"@subwallet/extension-base": "^1.3.66-0",
"@subwallet/extension-chains": "^1.3.66-0",
Expand Down
12 changes: 11 additions & 1 deletion packages/extension-base/src/koni/background/handlers/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { EvmProviderError } from '@subwallet/extension-base/background/errors/Ev
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers';
import { isSubscriptionRunning, unsubscribe } from '@subwallet/extension-base/background/handlers/subscriptions';
import { AddressCardanoTransactionBalance, AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AuthRequestV2, BitcoinProviderErrorType, BitcoinSendTransactionParams, BitcoinSendTransactionRequest, BitcoinSignatureRequest, BitcoinSignMessageParams, BitcoinSignMessageResult, BitcoinSignPsbtParams, BitcoinSignPsbtRequest, BitcoinSignPsbtResult, CardanoKeyType, CardanoProviderErrorType, CardanoSignatureRequest, CardanoTransactionDappConfig, ChainStakingMetadata, ChainType, ConfirmationsQueue, ConfirmationsQueueBitcoin, ConfirmationsQueueCardano, ConfirmationsQueueTon, ConfirmationType, CrowdloanItem, CrowdloanJson, CurrencyType, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, PsbtTransactionArg, RequestAccountExportPrivateKey, RequestCardanoSignData, RequestCardanoSignTransaction, RequestConfirmationComplete, RequestConfirmationCompleteBitcoin, RequestConfirmationCompleteCardano, RequestConfirmationCompleteTon, RequestCrowdloanContributions, RequestSettingsType, ResponseAccountExportPrivateKey, ResponseCardanoSignData, ResponseCardanoSignTransaction, ServiceInfo, SingleModeJson, StakingItem, StakingJson, StakingRewardItem, StakingRewardJson, StakingType, UiSettings } from '@subwallet/extension-base/background/KoniTypes';
import { AddressCardanoTransactionBalance, AddTokenRequestExternal, AmountData, APIItemState, ApiMap, AssetSetting, AuthRequestV2, BitcoinProviderErrorType, BitcoinSendTransactionParams, BitcoinSendTransactionRequest, BitcoinSignatureRequest, BitcoinSignMessageParams, BitcoinSignMessageResult, BitcoinSignPsbtParams, BitcoinSignPsbtRequest, BitcoinSignPsbtResult, CardanoKeyType, CardanoProviderErrorType, CardanoSignatureRequest, CardanoTransactionDappConfig, ChainStakingMetadata, ChainType, ConfirmationsQueue, ConfirmationsQueueBitcoin, ConfirmationsQueueCardano, ConfirmationsQueueTon, ConfirmationType, CrowdloanItem, CrowdloanJson, CurrencyType, EvmProviderErrorType, EvmSendTransactionParams, EvmSendTransactionRequest, EvmSignatureRequest, ExternalRequestPromise, ExternalRequestPromiseStatus, ExtrinsicType, MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState, NftCollection, NftItem, NftJson, NominatorMetadata, PsbtTransactionArg, RequestAccountExportPrivateKey, RequestCardanoSignData, RequestCardanoSignTransaction, RequestConfirmationComplete, RequestConfirmationCompleteBitcoin, RequestConfirmationCompleteCardano, RequestConfirmationCompleteTon, RequestCrowdloanContributions, RequestSettingsType, ResponseAccountExportPrivateKey, ResponseCardanoSignData, ResponseCardanoSignTransaction, ServiceInfo, SingleModeJson, StakingItem, StakingJson, StakingRewardItem, StakingRewardJson, StakingType, UiSettings } from '@subwallet/extension-base/background/KoniTypes';
import { RequestAuthorizeTab, RequestRpcSend, RequestRpcSubscribe, RequestRpcUnsubscribe, RequestSign, ResponseRpcListProviders, ResponseSigning } from '@subwallet/extension-base/background/types';
import { EnvConfig, MANTA_PAY_BALANCE_INTERVAL, REMIND_EXPORT_ACCOUNT } from '@subwallet/extension-base/constants';
import { convertErrorFormat, generateValidationProcess, PayloadValidated, ValidateStepFunction, validationAuthCardanoMiddleware, validationAuthMiddleware, validationAuthWCMiddleware, validationBitcoinConnectMiddleware, validationBitcoinSendTransactionMiddleware, validationBitcoinSignMessageMiddleware, validationBitcoinSignPsbtMiddleware, validationCardanoSignDataMiddleware, validationConnectMiddleware, validationEvmDataTransactionMiddleware, validationEvmSignMessageMiddleware } from '@subwallet/extension-base/core/logic-validation';
Expand Down Expand Up @@ -894,6 +894,16 @@ export default class KoniState {
};

public async disableChain (chainSlug: string): Promise<boolean> {
const assetSettings = await this.chainService.getAssetSettings();
const temporaryAssettings: Record<string, AssetSetting> = {};

Object.keys(assetSettings).forEach((key) => {
if (this.chainService.getAssetBySlug(key).originChain === chainSlug) {
temporaryAssettings[key] = assetSettings[key];
}
});

this.chainService.updateTemporarySettings(temporaryAssettings);
await this.chainService.updateAssetSettingByChain(chainSlug, false);

if (_MANTA_ZK_CHAIN_GROUP.includes(chainSlug)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,22 @@ interface Msg {
bounced: boolean,
opcode: string
}

interface TonApiJettonBalance {
balance: string;
jetton: {
address: string;
name: string;
symbol: string;
decimals: number;
};
}

export interface TonApiJettonResponse {
balances: TonApiJettonBalance[];
}

export interface TonApiAccountResponse {
address: string;
balance: number;
}
33 changes: 28 additions & 5 deletions packages/extension-base/src/services/balance-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import DetectAccountBalanceStore from '@subwallet/extension-base/stores/DetectAc
import { BalanceItem, BalanceJson, CommonOptimalTransferPath } from '@subwallet/extension-base/types';
import { addLazy, createPromiseHandler, isAccountAll, PromiseHandler, waitTimeout } from '@subwallet/extension-base/utils';
import { getKeypairTypeByAddress } from '@subwallet/keyring';
import { EthereumKeypairTypes, SubstrateKeypairTypes } from '@subwallet/keyring/types';
import { EthereumKeypairTypes, SubstrateKeypairTypes, TonKeypairTypes } from '@subwallet/keyring/types';
import keyring from '@subwallet/ui-keyring';
import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk';
import BigN from 'bignumber.js';
Expand Down Expand Up @@ -545,10 +545,33 @@ export class BalanceService implements StoppableServiceInterface {
}
});

const tonPromiseList = addresses.map((address) => {
const type = getKeypairTypeByAddress(address);
const typeValid = [...TonKeypairTypes].includes(type);

if (typeValid) {
return subwalletApiSdk.balanceDetectionApi.getTonTokenBalanceSlug(address)
.catch((e) => {
console.error(e);

return null;
});
} else {
return null;
}
});

const needEnableChains: string[] = [];
const needActiveTokens: string[] = [];

const balanceDataList = await Promise.all(promiseList);
const evmBalanceDataList = await Promise.all(evmPromiseList);
const tonBalanceDataList = await Promise.all(tonPromiseList);
const allBalanceDataLists = [
...evmBalanceDataList,
...tonBalanceDataList
];

const currentAssetSettings = await this.state.chainService.getAssetSettings();
const chainInfoMap = this.state.chainService.getChainInfoMap();
const detectBalanceChainSlugMap = this.state.chainService.detectBalanceChainSlugMap;
Expand Down Expand Up @@ -590,18 +613,18 @@ export class BalanceService implements StoppableServiceInterface {
}
}

for (const balanceData of evmBalanceDataList) {
for (const balanceData of allBalanceDataLists) {
if (balanceData) {
for (const tokenSlug of balanceData) {
const chainSlug = tokenSlug.split('-')[0];
const chainState = this.state.chainService.getChainStateByKey(chainSlug);
const existedKey = Object.keys(assetMap).find((v) => v.toLowerCase() === tokenSlug.toLowerCase());

// Cancel if chain is turned off by user
if (chainState && chainState.manualTurnOff) {
if (chainState?.manualTurnOff) {
continue;
}

const existedKey = Object.keys(assetMap).find((v) => v.toLowerCase() === tokenSlug.toLowerCase());

if (existedKey && !currentAssetSettings[existedKey]?.visible) {
needEnableChains.push(chainSlug);
needActiveTokens.push(existedKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
// Copyright 2019-2022 @subwallet/extension-base authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { ChainAssetMap, ChainInfoMap } from '@subwallet/chain-list';
import { _AssetType } from '@subwallet/chain-list/types';
import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
import { TON_CENTER_API_KEY, TON_OPCODES } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/consts';
import { AccountState, TxByMsgResponse } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/types';
import { AccountState, TonApiAccountResponse, TonApiJettonResponse, TxByMsgResponse } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/types';
import { getJettonTxStatus, retryTonTxStatus } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types';
import { _ChainConnectionStatus, _TonApi } from '@subwallet/extension-base/services/chain-service/types';
import { _getChainNativeTokenSlug } from '@subwallet/extension-base/services/chain-service/utils';
import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils';
import { TonWalletContract } from '@subwallet/keyring/types';
import { Cell } from '@ton/core';
import { Address, Contract, OpenedContract, TonClient } from '@ton/ton';
import BigN from 'bignumber.js';
import { BehaviorSubject } from 'rxjs';

export class TonApi implements _TonApi {
Expand Down Expand Up @@ -254,4 +258,45 @@ export class TonApi implements _TonApi {

return 'unknown';
}

async getTonTokenBalanceSlug (address: string): Promise<string[]> {
const tokenList = Object.values(ChainAssetMap).filter((asset) => asset.assetType === _AssetType.TEP74);
const chainInfo = ChainInfoMap[this.chainSlug];

const userFriendlyAddress = Address.parse(address).toString();
const tokenApiUrl = `https://tonapi.io/v2/accounts/${userFriendlyAddress}/jettons`;
const accountApiUrl = `https://tonapi.io/v2/accounts/${userFriendlyAddress}`;

try {
const [tokenDataResponse, accountDataResponse] = await Promise.all([
fetch(tokenApiUrl),
fetch(accountApiUrl)]
);

if (!tokenDataResponse.ok) {
return [];
}

const tokenData = await tokenDataResponse.json() as TonApiJettonResponse;
const accountData = await accountDataResponse.json() as TonApiAccountResponse;

const items = tokenData.balances.map((jettonBalance) => {
const tokenInfo = Object.values(tokenList).find((asset) => asset.metadata?.contractAddress === Address.parse(jettonBalance.jetton.address).toString());

if (!tokenInfo) {
return null;
}

return tokenInfo?.slug;
}).filter((item) => !!item) as string[];

if (new BigN(accountData.balance).gt(0)) {
items.push(_getChainNativeTokenSlug(chainInfo));
}

return items;
} catch (e) {
return [];
}
}
}
38 changes: 38 additions & 0 deletions packages/extension-base/src/services/chain-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ export class ChainService {

private logger: Logger;

private temporaryAssetSetting: Record<string, AssetSetting> | undefined;

constructor (dbService: DatabaseService, eventService: EventService) {
this.dbService = dbService;
this.eventService = eventService;
Expand Down Expand Up @@ -1647,6 +1649,15 @@ export class ChainService {
// Enable chain if not before
if (!targetChainState.active) {
targetChainState.active = true;

// enable native token
const nativeAsset = this.getNativeTokenInfo(chainSlug);
const currentAssetSettings = await this.getAssetSettings();

if (!currentAssetSettings[nativeAsset.slug].visible) {
currentAssetSettings[nativeAsset.slug] = { visible: true };
this.setAssetSettings(currentAssetSettings);
}
}

// It auto detects the change of api url to create new instance or reuse existed one
Expand Down Expand Up @@ -2186,6 +2197,26 @@ export class ChainService {
return this.assetSettingSubject.value;
}

public getTemporarySettings (): Record<string, AssetSetting> | undefined {
return this.temporaryAssetSetting;
}

public updateTemporarySettings (assetSettings: Record<string, AssetSetting>) {
if (!this.temporaryAssetSetting) {
this.temporaryAssetSetting = {};
}

this.temporaryAssetSetting = { ...this.temporaryAssetSetting, ...assetSettings };
}

public clearTemporarySettings (assetSlug: string) {
if (!this.temporaryAssetSetting) {
return;
}

delete this.temporaryAssetSetting[assetSlug];
}

public async updateAssetSetting (assetSlug: string, assetSetting: AssetSetting, autoEnableNativeToken?: boolean): Promise<boolean | undefined> {
const currentAssetSettings = await this.getAssetSettings();

Expand Down Expand Up @@ -2232,6 +2263,7 @@ export class ChainService {
const currentAssetSettings = await this.getAssetSettings();
const assetsByChain = this.getFungibleTokensByChain(chainSlug);
const priorityTokensMap = this.priorityTokensSubject.value || {};
const temporaryAssetSettings = this.getTemporarySettings();

const priorityTokensList = priorityTokensMap.token && typeof priorityTokensMap.token === 'object'
? Object.keys(priorityTokensMap.token)
Expand All @@ -2241,6 +2273,12 @@ export class ChainService {
if (visible) {
const isPriorityToken = priorityTokensList.includes(asset.slug);

if (temporaryAssetSettings) {
if (Object.keys(temporaryAssetSettings).includes(asset.slug) && temporaryAssetSettings[asset.slug].visible) {
currentAssetSettings[asset.slug] = { visible: true };
}
}

if (isPriorityToken || _isNativeToken(asset)) {
currentAssetSettings[asset.slug] = { visible: true };
}
Expand Down
15 changes: 9 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6261,13 +6261,16 @@ __metadata:
languageName: node
linkType: hard

"@subwallet-monorepos/subwallet-services-sdk@npm:0.1.13":
version: 0.1.13
resolution: "@subwallet-monorepos/subwallet-services-sdk@npm:0.1.13"
"@subwallet-monorepos/subwallet-services-sdk@npm:0.1.13-beta.3":
version: 0.1.13-beta.3
resolution: "@subwallet-monorepos/subwallet-services-sdk@npm:0.1.13-beta.3"
dependencies:
"@koniverse/utils": ^0.0.9
"@subwallet/chain-list": 0.2.120
checksum: 4a8cd823b055179a1795d6214d96c09be0118b668a6d62fb7677f9dbd175d0699694ce84867ce52984bf02629afefe2461140dcb40e805303c7c71dae78eb571
"@subwallet/chain-list": 0.2.121
"@ton/core": ^0.56.3
"@ton/crypto": ^3.2.0
"@ton/ton": ^15.0.0
checksum: 78e1b6ddc6776761c9af3b9fc4064330042645bba0246f3d6e850a1316c33df8ed8024c3297c188abbe3125f810ab55f92917ec2499bd9a53a5a7ef284b50c07
languageName: node
linkType: hard

Expand Down Expand Up @@ -6321,7 +6324,7 @@ __metadata:
"@snowbridge/registry": ^0.2.0
"@sora-substrate/type-definitions": ^1.17.7
"@substrate/connect": ^0.8.9
"@subwallet-monorepos/subwallet-services-sdk": 0.1.13
"@subwallet-monorepos/subwallet-services-sdk": 0.1.13-beta.3
"@subwallet/chain-list": 0.2.121
"@subwallet/extension-base": ^1.3.66-0
"@subwallet/extension-chains": ^1.3.66-0
Expand Down
Loading