diff --git a/packages/extension-base/package.json b/packages/extension-base/package.json index 165100dc171..65818f2f92b 100644 --- a/packages/extension-base/package.json +++ b/packages/extension-base/package.json @@ -90,6 +90,7 @@ "is-buffer": "^2.0.5", "joi": "^17.13.3", "json-rpc-engine": "^6.1.0", + "loglevel": "^1.8.1", "manta-extension-sdk": "^1.1.0", "moment": "^2.29.4", "protobufjs": "^7.5.4", diff --git a/packages/extension-base/src/background/handlers/helpers.ts b/packages/extension-base/src/background/handlers/helpers.ts index 5142efc4850..9f89a038bd5 100644 --- a/packages/extension-base/src/background/handlers/helpers.ts +++ b/packages/extension-base/src/background/handlers/helpers.ts @@ -1,14 +1,18 @@ // Copyright 2019-2022 @polkadot/extension authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const backgroundHelpersLogger = createLogger('BackgroundHelpers'); + export function withErrorLog (fn: () => unknown): void { try { const p = fn(); if (p && typeof p === 'object' && typeof (p as Promise).catch === 'function') { - (p as Promise).catch(console.error); + (p as Promise).catch((e) => backgroundHelpersLogger.error('Error in withErrorLog promise', e)); } } catch (e) { - console.error(e); + backgroundHelpersLogger.error('Error in withErrorLog', e); } } diff --git a/packages/extension-base/src/background/handlers/subscriptions.ts b/packages/extension-base/src/background/handlers/subscriptions.ts index dd2d105a123..72d254983a5 100644 --- a/packages/extension-base/src/background/handlers/subscriptions.ts +++ b/packages/extension-base/src/background/handlers/subscriptions.ts @@ -3,9 +3,12 @@ import type { MessageTypesWithSubscriptions, SubscriptionMessageTypes } from '../types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + type Subscriptions = Record; const subscriptions: Subscriptions = {}; +const subscriptionsLogger = createLogger('Subscriptions'); // return a subscription callback, that will send the data to the caller via the port export function createSubscription (id: string, port: chrome.runtime.Port): (data: SubscriptionMessageTypes[TMessageType]) => void { @@ -27,6 +30,6 @@ export function unsubscribe (id: string): void { if (subscriptions[id]) { delete subscriptions[id]; } else { - console.error(`Unable to unsubscribe from ${id}`); + subscriptionsLogger.error(`Unable to unsubscribe from ${id}`); } } diff --git a/packages/extension-base/src/constants/index.ts b/packages/extension-base/src/constants/index.ts index 841cca2aa7a..5d94c43f117 100644 --- a/packages/extension-base/src/constants/index.ts +++ b/packages/extension-base/src/constants/index.ts @@ -58,9 +58,13 @@ export const getSupportTokenPayFeeChain = () => { return Object.values(_SUPPORT_TOKEN_PAY_FEE_GROUP).flat(); }; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const constantsLogger = createLogger('Constants'); + export const isChainSupportTokenPayFee = (chainSlug: string): boolean => { if (!chainSlug) { - console.error('You must provide chain slug!'); + constantsLogger.error('You must provide chain slug!'); return false; } diff --git a/packages/extension-base/src/core/logic-validation/request.ts b/packages/extension-base/src/core/logic-validation/request.ts index 7790ba63f75..5e78a8a8a1d 100644 --- a/packages/extension-base/src/core/logic-validation/request.ts +++ b/packages/extension-base/src/core/logic-validation/request.ts @@ -16,8 +16,11 @@ import { BN_ZERO, combineEthFee, createPromiseHandler, isSameAddress, reformatAd import { validateAddressNetwork } from '@subwallet/extension-base/utils/cardano'; import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction'; import { getId } from '@subwallet/extension-base/utils/getId'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isCardanoAddress, isCardanoBaseAddress, isCardanoRewardAddress, isSubstrateAddress } from '@subwallet/keyring'; import { KeyringPair } from '@subwallet/keyring/types'; + +const logicValidationLogger = createLogger('LogicValidation'); import { getBitcoinAddressInfo } from '@subwallet/keyring/utils'; import { isBitcoinAddress } from '@subwallet/keyring/utils/address/validate'; import { keyring } from '@subwallet/ui-keyring'; @@ -262,7 +265,7 @@ export async function validationConnectMiddleware (koni: KoniState, url: string, const [message, name] = convertErrorMessage(message_); const error = new EvmProviderError(EvmProviderErrorType.CHAIN_DISCONNECTED, message, undefined, name); - console.error(error); + logicValidationLogger.error('Validation error: chain disconnected', error); errors.push(error); }; @@ -356,7 +359,7 @@ export async function validationEvmDataTransactionMiddleware (koni: KoniState, u const [message, name] = convertErrorMessage(message_); const error = new TransactionError(BasicTxErrorType.INVALID_PARAMS, message, undefined, name); - console.error(error); + logicValidationLogger.error('Validation error: invalid params', error); errors.push(error); }; @@ -555,7 +558,7 @@ export async function validationEvmSignMessageMiddleware (koni: KoniState, url: const [message, name] = convertErrorMessage(message_); const error = new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, message, undefined, name); - console.error(error); + logicValidationLogger.error('Validation error: invalid params in evm signature', error); errors.push(error); }; @@ -614,7 +617,7 @@ export async function validationEvmSignMessageMiddleware (koni: KoniState, url: throw new Error('Unsupported action'); } } catch (e) { - console.error(e); + logicValidationLogger.error('Error in validationEvmSignMessageMiddleware', e); handleError((e as Error).message); } } else { @@ -760,7 +763,7 @@ export async function validationCardanoSignDataMiddleware (koni: KoniState, url: const [message, name] = convertErrorMessage(message_); const error = new CardanoProviderError(CardanoProviderErrorType.INVALID_REQUEST, message, undefined, name); - console.error(error); + logicValidationLogger.error('Validation error: invalid request in cardano signature', error); errors.push(error); }; @@ -823,7 +826,7 @@ export async function validationBitcoinConnectMiddleware (koni: KoniState, url: const [message, name] = convertErrorMessage(message_); const error = new TransactionError(BasicTxErrorType.INVALID_PARAMS, message, undefined, name); - console.error(error); + logicValidationLogger.error('Validation error: invalid params', error); errors.push(error); }; @@ -1074,7 +1077,7 @@ export async function validationBitcoinSendTransactionMiddleware (koni: KoniStat const [message, name] = [t('bg.TRANSACTION.core.validation.request.enableChainOnExtension', { replace: { chain: chainInfo.name } }), t('bg.TRANSACTION.core.validation.request.networkNotEnabled')]; const error = new BitcoinProviderError(BitcoinProviderErrorType.INVALID_PARAMS, message, undefined, name); - console.error(error); + logicValidationLogger.error('Validation error: network not enabled for bitcoin transaction', error); errors.push(error); } else { handleError(message); diff --git a/packages/extension-base/src/core/utils.ts b/packages/extension-base/src/core/utils.ts index 88a63121f39..914535fa539 100644 --- a/packages/extension-base/src/core/utils.ts +++ b/packages/extension-base/src/core/utils.ts @@ -16,6 +16,10 @@ import { getBitcoinAddressInfo, validateBitcoinAddress } from '@subwallet/keyrin import { AnyJson } from '@polkadot/types/types'; import { isEthereumAddress } from '@polkadot/util-crypto'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const coreUtilsLogger = createLogger('CoreUtils'); + export function getStrictMode (type: string, extrinsicType?: ExtrinsicType) { if (type === BalanceAccountType.FrameSystemAccountInfo) { return !extrinsicType || ![ExtrinsicType.TRANSFER_BALANCE].includes(extrinsicType); @@ -235,7 +239,7 @@ export const _isSufficientToken = async (tokenInfo: _ChainAsset, substrateApi: _ } } } catch (e) { - console.error(e); + coreUtilsLogger.error('Error in core utils', e); } } diff --git a/packages/extension-base/src/koni/api/coingecko.ts b/packages/extension-base/src/koni/api/coingecko.ts index 55872495105..44cb060828c 100644 --- a/packages/extension-base/src/koni/api/coingecko.ts +++ b/packages/extension-base/src/koni/api/coingecko.ts @@ -3,8 +3,11 @@ import { CurrencyJson, CurrencyType, ExchangeRateJSON, PriceJson } from '@subwallet/extension-base/background/KoniTypes'; import { staticData, StaticKey } from '@subwallet/extension-base/utils/staticData'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import axios, { AxiosResponse } from 'axios'; +const coingeckoLogger = createLogger('Coingecko'); + interface GeckoItem { id: string, name: string, @@ -46,7 +49,7 @@ export const getTokenPrice = async (priceIds: Set, currencyCode: Currenc } if (rs?.status !== 200) { - console.warn('Failed to get token price'); + coingeckoLogger.warn('Failed to get token price'); } return rs; @@ -58,11 +61,11 @@ export const getTokenPrice = async (priceIds: Set, currencyCode: Currenc try { rs = await axios.get('https://api-cache.subwallet.app/exchange-rate'); } catch (e) { - console.warn('Failed to get exchange rate'); + coingeckoLogger.warn('Failed to get exchange rate', e); } if (rs?.status !== 200) { - console.warn('Failed to get exchange rate'); + coingeckoLogger.warn('Failed to get exchange rate - invalid status'); } return rs; @@ -109,7 +112,7 @@ export const getTokenPrice = async (priceIds: Set, currencyCode: Currenc price24hMap } as PriceJson; } catch (err) { - console.error(err); + coingeckoLogger.error('Error fetching price data', err); throw err; } }; diff --git a/packages/extension-base/src/koni/api/dotsama/crowdloan.ts b/packages/extension-base/src/koni/api/dotsama/crowdloan.ts index de7960e4db9..3ab3842759f 100644 --- a/packages/extension-base/src/koni/api/dotsama/crowdloan.ts +++ b/packages/extension-base/src/koni/api/dotsama/crowdloan.ts @@ -9,8 +9,11 @@ import registry from '@subwallet/extension-base/koni/api/dotsama/typeRegistry'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { fetchJson, getAddressesByChainType, reformatAddress } from '@subwallet/extension-base/utils'; import { fetchStaticData } from '@subwallet/extension-base/utils/fetchStaticData'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { DeriveOwnContributions } from '@polkadot/api-derive/types'; + +const crowdloanLogger = createLogger('Crowdloan'); import { BN } from '@polkadot/util'; const STATUS_MAP: Record<_FundStatus, CrowdloanParaState> = { @@ -74,7 +77,7 @@ function getRPCCrowdloan (parentAPI: _SubstrateApi, fundInfo: _CrowdloanFund, he .then((unsub) => { unsub(); }) - .catch(console.error); + .catch((e) => crowdloanLogger.error('Error unsubscribing from crowdloan', e)); }; } @@ -109,7 +112,7 @@ export const subscribeAcalaContributeInterval = (polkadotAddresses: string[], fu }; callback(rs); - }).catch(console.error); + }).catch((e) => crowdloanLogger.error('Error fetching Acala contribution info', e)); }; getContributeInfo(); diff --git a/packages/extension-base/src/koni/api/dotsama/domain.ts b/packages/extension-base/src/koni/api/dotsama/domain.ts index 57c7af86f52..10bd2f37562 100644 --- a/packages/extension-base/src/koni/api/dotsama/domain.ts +++ b/packages/extension-base/src/koni/api/dotsama/domain.ts @@ -5,6 +5,10 @@ import { resolveAddressToDomain, resolveDomainToAddress, SupportedChainId } from import { ApiPromise } from '@polkadot/api'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const domainResolverLogger = createLogger('DomainResolver'); + export const ENS_SUFFIX = '.eth'; export const TZERO_ID_SUFFIX = '.tzero'; @@ -42,7 +46,7 @@ export async function resolveAzeroDomainToAddress (domain: string, chain: string ); if (primaryDomains.error) { - console.debug(primaryDomains.error); + domainResolverLogger.debug('Error resolving domain to address', primaryDomains.error); } return primaryDomains?.address || undefined; @@ -64,7 +68,7 @@ export async function resolveAzeroAddressToDomain (address: string, chain: strin ); if (primaryDomains.error) { - console.debug(primaryDomains.error); + domainResolverLogger.debug('Error resolving address to domain', primaryDomains.error); } return primaryDomains?.primaryDomain || undefined; diff --git a/packages/extension-base/src/koni/api/nft/acala_nft/index.ts b/packages/extension-base/src/koni/api/nft/acala_nft/index.ts index adf09fbebc1..7e5468cad1e 100644 --- a/packages/extension-base/src/koni/api/nft/acala_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/acala_nft/index.ts @@ -6,6 +6,9 @@ import { getRandomIpfsGateway } from '@subwallet/extension-base/koni/api/nft/con import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { isUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const acalaNftLogger = createLogger('AcalaNft'); interface AssetId { classId: string | number, @@ -157,7 +160,7 @@ export class AcalaNftApi extends BaseNftApi { params.updateCollection(this.chain, parsedCollection); })); } catch (e) { - console.error(`${this.chain}`, e); + acalaNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/assethub_nft/index.ts b/packages/extension-base/src/koni/api/nft/assethub_nft/index.ts index 681efc80de4..ebc4517c98d 100644 --- a/packages/extension-base/src/koni/api/nft/assethub_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/assethub_nft/index.ts @@ -5,6 +5,9 @@ import { AssetHubNftType, NftCollection, NftItem } from '@subwallet/extension-ba import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { isUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const assethubNftLogger = createLogger('AssethubNft'); interface AssetId { classId: string | number, @@ -199,7 +202,7 @@ export default class AssetHubNftsPalletApi extends BaseNftApi { params.updateCollection(this.chain, parsedCollection); })); } catch (e) { - console.error(`${this.chain}`, e); + assethubNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/assethub_unique/index.ts b/packages/extension-base/src/koni/api/nft/assethub_unique/index.ts index 71c7c682b49..068b198e983 100644 --- a/packages/extension-base/src/koni/api/nft/assethub_unique/index.ts +++ b/packages/extension-base/src/koni/api/nft/assethub_unique/index.ts @@ -5,6 +5,9 @@ import { AssetHubNftType, NftCollection, NftItem } from '@subwallet/extension-ba import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { isUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const assethubUniqueLogger = createLogger('AssethubUnique'); interface AssetId { classId: string | number, @@ -167,7 +170,7 @@ export default class AssetHubUniquesPalletApi extends BaseNftApi { params.updateCollection(this.chain, parsedCollection); })); } catch (e) { - console.error(`${this.chain}`, e); + assethubUniqueLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/bit.country/index.ts b/packages/extension-base/src/koni/api/nft/bit.country/index.ts index 9adb4bb1925..db2a5022a9d 100644 --- a/packages/extension-base/src/koni/api/nft/bit.country/index.ts +++ b/packages/extension-base/src/koni/api/nft/bit.country/index.ts @@ -6,9 +6,12 @@ import { BIT_AVATAR_API, BIT_COUNTRY_IPFS_SERVER, BIT_COUNTRY_LAND_ESTATE_METADA import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { isUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BN_ZERO, hexToBn } from '@polkadot/util'; +const bitCountryNftLogger = createLogger('BitCountryNft'); + interface AssetId { classId: string | number, tokenId: string | number, @@ -126,7 +129,7 @@ export class BitCountryNftApi extends BaseNftApi { try { metaverseId = hexToBn(hexMetaverseId); } catch (e) { - console.warn('Error parsing metaverse id', e); + bitCountryNftLogger.warn('Error parsing metaverse id', e); } return { @@ -217,7 +220,7 @@ export class BitCountryNftApi extends BaseNftApi { params.updateCollection(this.chain, parsedCollection); })); } catch (e) { - console.error(`${this.chain}`, e); + bitCountryNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/blobinscription/index.ts b/packages/extension-base/src/koni/api/nft/blobinscription/index.ts index dd6eec3b6fe..c0e9b2404b1 100644 --- a/packages/extension-base/src/koni/api/nft/blobinscription/index.ts +++ b/packages/extension-base/src/koni/api/nft/blobinscription/index.ts @@ -6,9 +6,12 @@ import { COLLECT_ID } from '@subwallet/extension-base/koni/api/nft/blobinscripti import { ALC, getNftDetail, NftResponse, RemarkData, transferPayload } from '@subwallet/extension-base/koni/api/nft/blobinscription/types'; import { AVAIL_LIGHT_CLIENT_NFT } from '@subwallet/extension-base/koni/api/nft/config'; import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { hexToString } from '@polkadot/util'; +const blobInscriptionLogger = createLogger('BlobInscription'); + export class BlobInscriptionApi extends BaseNftApi { endpoint = AVAIL_LIGHT_CLIENT_NFT; @@ -162,7 +165,7 @@ export class BlobInscriptionApi extends BaseNftApi { } })); } catch (error) { - console.error('Failed to fetch blob inscription', error); + blobInscriptionLogger.error('Failed to fetch blob inscription', error); } } diff --git a/packages/extension-base/src/koni/api/nft/evm_nft/index.ts b/packages/extension-base/src/koni/api/nft/evm_nft/index.ts index 1296be6d653..8d01fd8bc3c 100644 --- a/packages/extension-base/src/koni/api/nft/evm_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/evm_nft/index.ts @@ -9,9 +9,12 @@ import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/ import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isEthereumAddress } from '@polkadot/util-crypto'; +const evmNftLogger = createLogger('EvmNft'); + export class EvmNftApi extends BaseNftApi { evmContracts: _ChainAsset[] = []; @@ -151,14 +154,14 @@ export class EvmNftApi extends BaseNftApi { ownItem = true; } } catch (e) { - console.error(`${this.chain}`, e); + evmNftLogger.error(`Error handling NFT for chain ${this.chain}`, e); } } })); nftOwnerMap[address] = nftIds; } catch (e) { - console.error(`${this.chain}`, e); + evmNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } })); diff --git a/packages/extension-base/src/koni/api/nft/index.ts b/packages/extension-base/src/koni/api/nft/index.ts index f6f1016303d..7a304923afc 100644 --- a/packages/extension-base/src/koni/api/nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/index.ts @@ -19,8 +19,11 @@ import { _NFT_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-servi import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { _isChainSupportEvmNft, _isChainSupportNativeNft, _isChainSupportWasmNft, _isSupportOrdinal } from '@subwallet/extension-base/services/chain-service/utils'; import { getAddressesByChainType, targetIsWeb } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import AssetHubNftsPalletApi from './assethub_nft'; + +const nftApiLogger = createLogger('NftApi'); import { RariNftApi } from './rari'; import { OdysseyNftApi } from './story_odyssey_nft'; import { TernoaNftApi } from './ternoa_nft'; @@ -223,7 +226,7 @@ export class NftHandler { this.needSetupApi = false; } } catch (e) { - console.error(e); + nftApiLogger.error('Error in NftHandler', e); } } diff --git a/packages/extension-base/src/koni/api/nft/karura_nft/index.ts b/packages/extension-base/src/koni/api/nft/karura_nft/index.ts index 4fd7395c036..12d5adfd83c 100644 --- a/packages/extension-base/src/koni/api/nft/karura_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/karura_nft/index.ts @@ -6,6 +6,9 @@ import { getRandomIpfsGateway } from '@subwallet/extension-base/koni/api/nft/con import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { isUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const karuraNftLogger = createLogger('KaruraNft'); interface AssetId { classId: string | number, @@ -163,7 +166,7 @@ export class KaruraNftApi extends BaseNftApi { params.updateCollection(this.chain, parsedCollection); })); } catch (e) { - console.error(`${this.chain}`, e); + karuraNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/quartz_nft/index.ts b/packages/extension-base/src/koni/api/nft/quartz_nft/index.ts index 01c307b6403..b52aadf8dbc 100644 --- a/packages/extension-base/src/koni/api/nft/quartz_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/quartz_nft/index.ts @@ -5,9 +5,12 @@ import { NftCollection, NftItem } from '@subwallet/extension-base/background/Kon import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { hexToStr, hexToUTF16, parseIpfsLink, utf16ToString } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { deserializeNft } from './protobuf'; +const quartzNftLogger = createLogger('QuartzNft'); + interface CollectionProperties { schemaVersion: string, offchainSchema: string, @@ -218,7 +221,7 @@ export default class QuartzNftApi extends BaseNftApi { } })); } catch (e) { - console.error(`${this.chain}`, e); + quartzNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/quartz_nft/protobuf.ts b/packages/extension-base/src/koni/api/nft/quartz_nft/protobuf.ts index 5ea2bbf3845..0f181e26610 100644 --- a/packages/extension-base/src/koni/api/nft/quartz_nft/protobuf.ts +++ b/packages/extension-base/src/koni/api/nft/quartz_nft/protobuf.ts @@ -3,6 +3,10 @@ import { Root } from 'protobufjs'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const quartzProtobufLogger = createLogger('QuartzProtobuf'); + function defineMessage (schema: string) { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument return Root.fromJSON(JSON.parse(schema)); @@ -26,7 +30,7 @@ function convertEnumToString (value: any, key: string, NFTMeta: any, locale: any result = translationObject[locale]; } } catch (e) { - console.log('Error parsing schema when trying to convert enum to string: ', e); + quartzProtobufLogger.error('Error parsing schema when trying to convert enum to string', e); } // eslint-disable-next-line @typescript-eslint/no-unsafe-return diff --git a/packages/extension-base/src/koni/api/nft/rari/index.ts b/packages/extension-base/src/koni/api/nft/rari/index.ts index 8aca1f0126c..8af22e078f7 100644 --- a/packages/extension-base/src/koni/api/nft/rari/index.ts +++ b/packages/extension-base/src/koni/api/nft/rari/index.ts @@ -2,9 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BaseNftApi, HandleNftParams } from '../nft'; +const rariNftLogger = createLogger('RariNft'); + const options = { method: 'GET', headers: { @@ -63,7 +66,7 @@ export class RariNftApi extends BaseNftApi { ) .then((response) => response.json()) .catch((err) => { - console.error(err); + rariNftLogger.error('Error fetching Rari NFT', err); return null; }) as NftResponse; diff --git a/packages/extension-base/src/koni/api/nft/rmrk_nft/index.ts b/packages/extension-base/src/koni/api/nft/rmrk_nft/index.ts index fbae27554a8..2000da7338a 100644 --- a/packages/extension-base/src/koni/api/nft/rmrk_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/rmrk_nft/index.ts @@ -4,9 +4,12 @@ import { NftCollection, NftItem, RMRK_VER } from '@subwallet/extension-base/background/KoniTypes'; import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { isUrl, reformatAddress } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { SINGULAR_V1_COLLECTION_ENDPOINT, SINGULAR_V2_COLLECTION_ENDPOINT, SINGULAR_V2_ENDPOINT } from '../config'; +const rmrkNftLogger = createLogger('RmrkNft'); + enum RMRK_SOURCE { BIRD_KANARIA = 'bird_kanaria', KANARIA = 'kanaria', @@ -160,7 +163,7 @@ export class RmrkNftApi extends BaseNftApi { } } } catch (e) { - console.log('error fetching RMRK NFT', e); + rmrkNftLogger.error('Error fetching RMRK NFT', e); } })); @@ -270,7 +273,7 @@ export class RmrkNftApi extends BaseNftApi { allCollectionMeta[item?.id as string] = { ...data }; } } catch (e) { - console.error(item.url, e); + rmrkNftLogger.error(`Error fetching RMRK NFT collection metadata for ${item.url}`, e); } })); @@ -297,7 +300,7 @@ export class RmrkNftApi extends BaseNftApi { params.updateCollection(this.chain, parsedCollection); }); } catch (e) { - console.error(`${this.chain}`, e); + rmrkNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/story_odyssey_nft/index.ts b/packages/extension-base/src/koni/api/nft/story_odyssey_nft/index.ts index 1af814a68a2..1afe347fd7a 100644 --- a/packages/extension-base/src/koni/api/nft/story_odyssey_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/story_odyssey_nft/index.ts @@ -2,10 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { ODYSSEY_ENDPOINT } from '../config'; import { BaseNftApi, HandleNftParams } from '../nft'; +const storyOdysseyNftLogger = createLogger('StoryOdysseyNft'); + interface OdysseyTokenMetadata { name: string; image: string; @@ -92,7 +95,7 @@ export class OdysseyNftApi extends BaseNftApi { return result.data.odyssey.erc721_token; } catch (err) { - console.error('Error:', err); + storyOdysseyNftLogger.error('Error fetching Odyssey NFT', err); return null; } @@ -104,7 +107,7 @@ export class OdysseyNftApi extends BaseNftApi { return (await response.json()) as UrlMetadata; } catch (err) { - console.error('Error:', err); + storyOdysseyNftLogger.error('Error fetching URL metadata', err); return null; } diff --git a/packages/extension-base/src/koni/api/nft/ternoa_nft/index.ts b/packages/extension-base/src/koni/api/nft/ternoa_nft/index.ts index 117fefc3c1a..b2e7bd6583e 100644 --- a/packages/extension-base/src/koni/api/nft/ternoa_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/ternoa_nft/index.ts @@ -4,10 +4,13 @@ import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { baseParseIPFSUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { decodeAddress, encodeAddress } from '@polkadot/util-crypto'; import { TERNOA_MAINNET_CLIENT_NFT, TERNOA_MAINNET_GATEWAY } from '../config'; + +const ternoaNftLogger = createLogger('TernoaNft'); import { BaseNftApi, HandleNftParams } from '../nft'; interface NftMetadata { @@ -104,7 +107,7 @@ export class TernoaNftApi extends BaseNftApi { return { metadata: nft, detail: nftDetail }; } catch (err) { - console.error('Error:', err); + ternoaNftLogger.error('Error fetching NFT detail', err); return null; } @@ -112,7 +115,7 @@ export class TernoaNftApi extends BaseNftApi { return nftDetails.filter((nft) => nft !== null) as Array<{ metadata: NftMetadata; detail: NftDetail }>; } catch (err) { - console.error('Error:', err); + ternoaNftLogger.error('Error fetching NFT details', err); return null; } @@ -152,7 +155,7 @@ export class TernoaNftApi extends BaseNftApi { return collectionDetail; } catch (err) { - console.error('Error:', err); + ternoaNftLogger.error('Error fetching collection detail', err); return null; } diff --git a/packages/extension-base/src/koni/api/nft/transfer.ts b/packages/extension-base/src/koni/api/nft/transfer.ts index 2e2fd60154a..640649a389d 100644 --- a/packages/extension-base/src/koni/api/nft/transfer.ts +++ b/packages/extension-base/src/koni/api/nft/transfer.ts @@ -5,6 +5,9 @@ import { AssetHubNftType } from '@subwallet/extension-base/background/KoniTypes' import { SUPPORTED_TRANSFER_SUBSTRATE_CHAIN_NAME } from '@subwallet/extension-base/koni/api/nft/config'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const nftTransferLogger = createLogger('NftTransfer'); interface CollectionInfo { limits: { @@ -23,7 +26,7 @@ export function acalaGetExtrinsic (substrateApi: _SubstrateApi, senderAddress: s return substrateApi.api.tx.nft.transfer(recipientAddress, [collectionId, itemId]); } catch (e) { - console.error(e); + nftTransferLogger.error('Error in acalaGetExtrinsic', e); return null; } @@ -44,7 +47,7 @@ export function rmrkGetExtrinsic (substrateApi: _SubstrateApi, senderAddress: st return substrateApi.api.tx.system.remark(parsedRemark); } catch (e) { - console.error(e); + nftTransferLogger.error('Error in rmrkGetExtrinsic', e); return null; } @@ -67,7 +70,7 @@ export async function uniqueGetExtrinsic (substrateApi: _SubstrateApi, senderAdd return null; } } catch (e) { - console.error(e); + nftTransferLogger.error('Error in uniqueGetExtrinsic', e); return null; } @@ -87,7 +90,7 @@ export function assetHubGetExtrinsic (substrateApi: _SubstrateApi, senderAddress return null; } catch (e) { - console.error(e); + nftTransferLogger.error('Error in assetHubGetExtrinsic', e); return null; } diff --git a/packages/extension-base/src/koni/api/nft/unique_network_nft/index.ts b/packages/extension-base/src/koni/api/nft/unique_network_nft/index.ts index 811b8ac9c73..af2c23604b2 100644 --- a/packages/extension-base/src/koni/api/nft/unique_network_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/unique_network_nft/index.ts @@ -6,9 +6,12 @@ import { OPAL_SCAN_ENDPOINT, QUARTZ_SCAN_ENDPOINT, UNIQUE_IPFS_GATEWAY, UNIQUE_S import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _NFT_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants'; import { baseParseIPFSUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { decodeAddress, encodeAddress } from '@polkadot/util-crypto'; +const uniqueNetworkNftLogger = createLogger('UniqueNetworkNft'); + interface NftAttribute { trait_type: string; value: any; @@ -160,7 +163,7 @@ export class UniqueNftApi extends BaseNftApi { } })); } catch (e) { - console.error(`Failed to fetch ${this.chain} nft`, e); + uniqueNetworkNftLogger.error(`Failed to fetch ${this.chain} nft`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/unique_nft/index.ts b/packages/extension-base/src/koni/api/nft/unique_nft/index.ts index 9b15376e2a2..3b92f31866e 100644 --- a/packages/extension-base/src/koni/api/nft/unique_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/unique_nft/index.ts @@ -5,9 +5,12 @@ import { NftCollection, NftItem } from '@subwallet/extension-base/background/Kon import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { hexToStr, hexToUTF16, utf16ToString } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { deserializeNft } from './protobuf'; +const uniqueNftLogger = createLogger('UniqueNft'); + interface Collection { SchemaVersion: string, OffchainSchema: string, @@ -209,7 +212,7 @@ export default class UniqueNftApi extends BaseNftApi { })); })); } catch (e) { - console.error(`${this.chain}`, e); + uniqueNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/unique_nft/protobuf.ts b/packages/extension-base/src/koni/api/nft/unique_nft/protobuf.ts index 71f6459c9eb..60597c78e78 100644 --- a/packages/extension-base/src/koni/api/nft/unique_nft/protobuf.ts +++ b/packages/extension-base/src/koni/api/nft/unique_nft/protobuf.ts @@ -3,12 +3,16 @@ import { Root } from 'protobufjs'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const uniqueProtobufLogger = createLogger('UniqueProtobuf'); + function defineMessage (schema: string) { try { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument return Root.fromJSON(JSON.parse(schema)); } catch (e) { - console.log('Error parsing JSON schema', e); + uniqueProtobufLogger.error('Error parsing JSON schema', e); return null; } @@ -32,7 +36,7 @@ function convertEnumToString (value: any, key: string, NFTMeta: any, locale: any result = translationObject[locale]; } } catch (e) { - console.log('Error parsing schema when trying to convert enum to string: ', e); + uniqueProtobufLogger.error('Error parsing schema when trying to convert enum to string', e); } // eslint-disable-next-line @typescript-eslint/no-unsafe-return diff --git a/packages/extension-base/src/koni/api/nft/unique_nft/uniqueNftV2.ts b/packages/extension-base/src/koni/api/nft/unique_nft/uniqueNftV2.ts index 71f677e8c0a..8094a8b05af 100644 --- a/packages/extension-base/src/koni/api/nft/unique_nft/uniqueNftV2.ts +++ b/packages/extension-base/src/koni/api/nft/unique_nft/uniqueNftV2.ts @@ -3,6 +3,9 @@ import { UNIQUE_SCAN_ENDPOINT } from '@subwallet/extension-base/koni/api/nft/config'; import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const uniqueNftV2Logger = createLogger('UniqueNftV2'); interface NftData { collection_id: number; @@ -57,7 +60,7 @@ export class UniqueNftApiV2 extends BaseNftApi { allNfts = allNfts.concat(nfts); })); } catch (e) { - console.error(`Failed to fetch ${this.chain} nft`, e); + uniqueNftV2Logger.error(`Failed to fetch ${this.chain} nft`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/vara_nft/index.ts b/packages/extension-base/src/koni/api/nft/vara_nft/index.ts index 97e5e638e6f..ffe307b5f95 100644 --- a/packages/extension-base/src/koni/api/nft/vara_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/vara_nft/index.ts @@ -4,8 +4,11 @@ import { NftCollection, NftItem } from '@subwallet/extension-base/background/KoniTypes'; import { VARA_SCAN_ENDPOINT } from '@subwallet/extension-base/koni/api/nft/config'; import { BaseNftApi, HandleNftParams } from '@subwallet/extension-base/koni/api/nft/nft'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { hexAddPrefix, u8aToHex } from '@polkadot/util'; + +const varaNftLogger = createLogger('VaraNft'); import { decodeAddress } from '@polkadot/util-crypto'; interface NftData { @@ -109,7 +112,7 @@ export class VaraNftApi extends BaseNftApi { } })); } catch (e) { - console.error(`Failed to fetch ${this.chain} nft`, e); + varaNftLogger.error(`Failed to fetch ${this.chain} nft`, e); } } diff --git a/packages/extension-base/src/koni/api/nft/wasm_nft/index.ts b/packages/extension-base/src/koni/api/nft/wasm_nft/index.ts index 3d05cde7dcf..9c0693b764f 100644 --- a/packages/extension-base/src/koni/api/nft/wasm_nft/index.ts +++ b/packages/extension-base/src/koni/api/nft/wasm_nft/index.ts @@ -11,8 +11,11 @@ import { collectionApiFromArtZero, collectionDetailApiFromArtZero, externalUrlOn import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; import { isUrl } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { ApiPromise } from '@polkadot/api'; + +const wasmNftLogger = createLogger('WasmNft'); import { ContractPromise } from '@polkadot/api-contract'; import { isEthereumAddress } from '@polkadot/util-crypto'; @@ -42,7 +45,7 @@ async function isArtZeroFeaturedCollection (networkKey: string, contractAddress: body: urlencoded }).then((resp) => { resolve(resp.json()); - }).catch(console.error); + }).catch((e) => wasmNftLogger.error('Error fetching collection info', e)); }); const collectionInfo = await Promise.race([ @@ -425,7 +428,7 @@ export class WasmNftApi extends BaseNftApi { tokenUri = ((tokenUriObj.ok || tokenUriObj.Ok) as string[])[0]; } } catch (e) { - console.debug(e); + wasmNftLogger.debug('Error getting token URI', e); } if (!tokenUri) { @@ -468,7 +471,7 @@ export class WasmNftApi extends BaseNftApi { nftOwnerMap[address] = nftIds; } catch (e) { - console.error(`${this.chain}`, e); + wasmNftLogger.error(`Error handling NFTs for chain ${this.chain}`, e); } })); diff --git a/packages/extension-base/src/koni/api/staking/bonding/astar.ts b/packages/extension-base/src/koni/api/staking/bonding/astar.ts index cc308c5a09d..08986013f92 100644 --- a/packages/extension-base/src/koni/api/staking/bonding/astar.ts +++ b/packages/extension-base/src/koni/api/staking/bonding/astar.ts @@ -14,6 +14,10 @@ import { Codec } from '@polkadot/types/types'; import { BN, BN_ZERO } from '@polkadot/util'; import { isEthereumAddress } from '@polkadot/util-crypto'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const astarStakingLogger = createLogger('AstarStaking'); + const convertAddress = (address: string) => { return isEthereumAddress(address) ? address.toLowerCase() : address; }; @@ -24,7 +28,7 @@ const fetchDApps = async (network: string) => { method: 'GET' }).then((resp) => { resolve(resp.json()); - }).catch(console.error); + }).catch((e) => astarStakingLogger.error('Error fetching dApps', e)); }); }; @@ -55,7 +59,7 @@ export async function getAstarStakingMetadata (chain: string, substrateApi: _Sub method: 'GET' }).then((resp) => { resolve(resp.json()); - }).catch(console.error); + }).catch((e) => astarStakingLogger.error('Error fetching APR', e)); }); const timeout = new Promise((resolve) => { diff --git a/packages/extension-base/src/koni/api/staking/bonding/utils.ts b/packages/extension-base/src/koni/api/staking/bonding/utils.ts index 47b9b88b3a8..82bd1158c9d 100644 --- a/packages/extension-base/src/koni/api/staking/bonding/utils.ts +++ b/packages/extension-base/src/koni/api/staking/bonding/utils.ts @@ -18,6 +18,10 @@ import { ApiPromise } from '@polkadot/api'; import { Codec } from '@polkadot/types/types'; import { BN, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_THOUSAND, BN_ZERO, bnToU8a, stringToU8a, u8aConcat } from '@polkadot/util'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const stakingBondingUtilsLogger = createLogger('StakingBondingUtils'); + export interface PalletDappsStakingDappInfo { address: string, name: string, @@ -264,7 +268,7 @@ export async function calculateAnalogChainStakedReturn (): Promise, chain: string, stakingCallback: (networkKey: string, rs: StakingItem) => void, nominatorStateCallback: (rs: NominatorMetadata) => void) { const { symbol } = _getChainNativeTokenBasicInfo(chainInfoMap[chain]); @@ -178,6 +182,6 @@ export async function getNominationPoolReward (addresses: string[], chainInfoMap } })); } catch (e) { - console.debug(e); + relayChainStakingLogger.debug('Error in getRelayStakingOnChain', e); } } diff --git a/packages/extension-base/src/koni/api/staking/subsquidStaking.ts b/packages/extension-base/src/koni/api/staking/subsquidStaking.ts index 8936d3ae159..b4b6bfe2995 100644 --- a/packages/extension-base/src/koni/api/staking/subsquidStaking.ts +++ b/packages/extension-base/src/koni/api/staking/subsquidStaking.ts @@ -6,9 +6,12 @@ import { APIItemState, StakingRewardItem, StakingType } from '@subwallet/extensi import { INDEXER_SUPPORTED_STAKING_CHAINS, SUBSQUID_ENDPOINTS } from '@subwallet/extension-base/koni/api/staking/config'; import { _getChainSubstrateAddressPrefix, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { fetchJson, reformatAddress } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isEthereumAddress } from '@polkadot/util-crypto'; +const subsquidStakingLogger = createLogger('SubsquidStaking'); + interface RewardResponseItem { amount: string, blockNumber: string @@ -85,7 +88,7 @@ const getSubsquidStaking = async (accounts: string[], chain: string, chainInfoMa } } } catch (e) { - console.error(e); + subsquidStakingLogger.error('Error processing staking reward item', e); } if (stakingRewardItem.totalReward && parseFloat(stakingRewardItem.totalReward) > 0) { @@ -94,7 +97,7 @@ const getSubsquidStaking = async (accounts: string[], chain: string, chainInfoMa } })); } catch (e) { - console.debug(e); + subsquidStakingLogger.debug('Error in getSubsquidStaking', e); } }; @@ -112,6 +115,6 @@ export const getAllSubsquidStaking = async (accounts: string[], chainInfoMap: Re await getSubsquidStaking(accounts, network, chainInfoMap, callback); })); } catch (e) { - console.debug(e); + subsquidStakingLogger.debug('Error in getAllSubsquidStaking', e); } }; diff --git a/packages/extension-base/src/koni/background/cron.ts b/packages/extension-base/src/koni/background/cron.ts index 2ef0c6c0786..c7e3e5f6c02 100644 --- a/packages/extension-base/src/koni/background/cron.ts +++ b/packages/extension-base/src/koni/background/cron.ts @@ -11,8 +11,12 @@ import DatabaseService from '@subwallet/extension-base/services/storage-service/ import { waitTimeout } from '@subwallet/extension-base/utils'; import { Subject, Subscription } from 'rxjs'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + import KoniState from './handlers/State'; +const koniCronLogger = createLogger('KoniCron'); + export class KoniCron { subscriptions: KoniSubscription; public status: 'pending' | 'running' | 'stopped' = 'pending'; @@ -205,12 +209,12 @@ export class KoniCron { syncMantaPay = () => { if (this.state.isMantaPayEnabled) { - this.state.syncMantaPay().catch(console.warn); + this.state.syncMantaPay().catch((e) => koniCronLogger.warn('Error syncing MantaPay', e)); } }; fetchPoolInfo = () => { - this.state.earningService.runSubscribePoolsInfo().catch(console.error); + this.state.earningService.runSubscribePoolsInfo().catch((e) => koniCronLogger.error('Error fetching pool info', e)); }; fetchMktCampaignData = () => { @@ -242,13 +246,13 @@ export class KoniCron { addresses = this.state.keyringService.context.getDecodedAddresses(); if (!addresses.length) { - console.warn('[Cron] No decoded addresses found for ALL_ACCOUNT_KEY'); + koniCronLogger.warn('No decoded addresses found for ALL_ACCOUNT_KEY'); return; } this.state.nftDetectionService.fetchEvmCollectionsWithPreview(addresses) - .catch((err) => console.warn(`[Cron] NFT detection failed for ${address}:`, err)); + .catch((err) => koniCronLogger.warn(`NFT detection failed for ${address}`, err)); }; }; @@ -270,7 +274,7 @@ export class KoniCron { public async reloadStaking () { const address = this.state.keyringService.context.currentAccount.proxyId; - console.log('reload staking', address); + koniCronLogger.debug('reload staking', address); await waitTimeout(1800); diff --git a/packages/extension-base/src/koni/background/handlers/Extension.ts b/packages/extension-base/src/koni/background/handlers/Extension.ts index 11855a902bf..446fcab2556 100644 --- a/packages/extension-base/src/koni/background/handlers/Extension.ts +++ b/packages/extension-base/src/koni/background/handlers/Extension.ts @@ -28,6 +28,7 @@ import { getTuringCancelCompoundingExtrinsic, getTuringCompoundExtrinsic } from import { getPoolingBondingExtrinsic, getPoolingUnbondingExtrinsic, validatePoolBondingCondition, validateRelayUnbondingCondition } from '@subwallet/extension-base/koni/api/staking/bonding/relayChain'; import { YIELD_EXTRINSIC_TYPES } from '@subwallet/extension-base/koni/api/yield/helper/utils'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { RequestOptimalTransferProcess } from '@subwallet/extension-base/services/balance-service/helpers/process'; import { DEFAULT_CARDANO_TTL_OFFSET } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/consts'; import { isBounceableAddress } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; @@ -97,6 +98,8 @@ export function isJsonPayload (value: SignerPayloadJSON | SignerPayloadRaw): val return (value as SignerPayloadJSON).genesisHash !== undefined; } +const logger = createLogger('KoniExtension'); + export default class KoniExtension { #lockTimeOut: NodeJS.Timer | undefined = undefined; readonly #koniState: KoniState; @@ -142,7 +145,7 @@ export default class KoniExtension { }; const updateLatestSession = (time: number) => { - SWStorage.instance.setItem(LATEST_SESSION, JSON.stringify({ remind: true, timeCalculate: time })).catch(console.error); + SWStorage.instance.setItem(LATEST_SESSION, JSON.stringify({ remind: true, timeCalculate: time })).catch((error) => logger.error('Failed to update latest session', error)); }; this.#koniState.settingService.getSettings(updateTimeAutoLock); @@ -276,7 +279,7 @@ export default class KoniExtension { const url = `${chrome.runtime.getURL('index.html')}#${path}${subPath || ''}${paramString}`; if (!ALLOWED_PATH.includes(path)) { - console.error('Not allowed to open the url:', url); + logger.error('Not allowed to open the url:', url); return false; } @@ -396,7 +399,7 @@ export default class KoniExtension { const subscription = combineLatest({ chainInfoMap: chainInfoMapObservable, tokenInfoMap: tokenInfoMapObservable, accountProxies: accountObservable, contacts: contactObservable }).subscribe(({ accountProxies, chainInfoMap, contacts, tokenInfoMap }) => { combineFunction(chainInfoMap, tokenInfoMap, accountProxies, contacts) .then((rs) => cb(rs)) - .catch(console.error); + .catch((error) => logger.error('Error combining chain info map', error)); }); this.createUnsubscriptionHandle(id, () => { @@ -1091,7 +1094,7 @@ export default class KoniExtension { return true; } catch (e) { - console.error(e); + logger.error('Error in validation', e); return false; } @@ -1573,7 +1576,7 @@ export default class KoniExtension { inputData.value = transferAmount.value; } - console.log('PSPT transaction', transaction.toHex()); + logger.info('PSPT transaction', transaction.toHex()); } else { const substrateApi = this.#koniState.getSubstrateApi(chain); @@ -1880,7 +1883,7 @@ export default class KoniExtension { autoEnableNativeToken: false, tokenSlug: destinationTokenInfo.slug, assetSetting: { visible: true } - }).catch(console.error); + }).catch((error) => logger.error('Error enabling token', error)); } } catch (e) { } @@ -2186,7 +2189,7 @@ export default class KoniExtension { try { return await this.#koniState.upsertChainInfo(data); } catch (e) { - console.error(e); + logger.error('Error upserting chain info', e); return false; } @@ -2225,7 +2228,7 @@ export default class KoniExtension { try { return this.#koniState.refreshSubstrateApi(networkKey); } catch (e) { - console.error(e); + logger.error('Error refreshing substrate API', e); return false; } @@ -2296,7 +2299,7 @@ export default class KoniExtension { error: '' }; } catch (e) { - console.error(e); + logger.error('Error in request handler', e); return { success: false, @@ -2404,7 +2407,7 @@ export default class KoniExtension { next: ({ fee, freeBalance }) => { calculateMaxTransferable(id, _request, freeBalance, fee) .then(cb) - .catch(console.error); + .catch((error) => logger.error('Error calculating max transferable', error)); } }); @@ -2545,7 +2548,7 @@ export default class KoniExtension { }; error = (e as Error).message || e as string; - console.warn('Unable to estimate fee', e); + logger.warn('Unable to estimate fee', e); } return { @@ -2564,7 +2567,7 @@ export default class KoniExtension { next: ({ fee, freeBalance }) => { convertData(freeBalance, fee, _feeOptions, feeCustom) .then(cb) - .catch(console.error); + .catch((error) => logger.error('Error converting data', error)); } }); @@ -3908,17 +3911,17 @@ export default class KoniExtension { await this.saveCurrentAccountProxy({ address }); const unsubSyncProgress = await this.#koniState.chainService?.mantaPay?.subscribeSyncProgress(); - console.debug('Start initial sync for MantaPay'); + logger.debug('Start initial sync for MantaPay'); this.#koniState.initialSyncMantaPay(address) .then(() => { - console.debug('Finished initial sync for MantaPay'); + logger.debug('Finished initial sync for MantaPay'); this.#skipAutoLock = false; unsubSyncProgress && unsubSyncProgress(); }) .catch((e) => { - console.error('Error syncing MantaPay', e); + logger.error('Error syncing MantaPay', e); this.#skipAutoLock = false; unsubSyncProgress && unsubSyncProgress(); @@ -3954,11 +3957,11 @@ export default class KoniExtension { await this.saveCurrentAccountProxy({ address }); const unsubSyncProgress = await this.#koniState.chainService?.mantaPay?.subscribeSyncProgress(); - console.debug('Start initial sync for MantaPay'); + logger.debug('Start initial sync for MantaPay'); this.#koniState.initialSyncMantaPay(address) .then(() => { - console.debug('Finished initial sync for MantaPay'); + logger.debug('Finished initial sync for MantaPay'); this.#skipAutoLock = false; unsubSyncProgress && unsubSyncProgress(); @@ -3969,7 +3972,7 @@ export default class KoniExtension { }); }) .catch((e) => { - console.error('Error syncing MantaPay', e); + logger.error('Error syncing MantaPay', e); this.#skipAutoLock = false; unsubSyncProgress && unsubSyncProgress(); @@ -3994,7 +3997,7 @@ export default class KoniExtension { return !isActive && isBounceable; } catch (error) { - console.error(`Failed to validate address ${address} on chain ${chain}:`, error); + logger.error(`Failed to validate address ${address} on chain ${chain}:`, error); return false; } @@ -4780,7 +4783,7 @@ export default class KoniExtension { this.#koniState.transactionService.updateProcessStepStatus(step, { status: StepStatus.FAILED }); } - console.log('Error handling process step', e); + logger.error('Error handling process step', e); throw e; } @@ -5168,7 +5171,7 @@ export default class KoniExtension { unsub = _unsub; onRs(rs); }) - .catch(console.error); + .catch((error) => logger.error('Error in subscription', error)); } }); } @@ -5191,7 +5194,7 @@ export default class KoniExtension { return { isPassConfirmation: true, signAfterCreate: (id: string) => { - this.signingApprovePasswordV2({ id }).catch(console.log); + this.signingApprovePasswordV2({ id }).catch((error) => logger.error('Error signing after create', error)); } }; } else { @@ -5270,7 +5273,7 @@ export default class KoniExtension { try { this.#koniState.inappNotificationService.migrateNotificationProxyId(proxyIds, newProxyId, newName); } catch (error) { - console.error('Error on migrating notification for unified account migration', error); + logger.error('Error on migrating notification for unified account migration', error); } return response; diff --git a/packages/extension-base/src/koni/background/handlers/Mobile.ts b/packages/extension-base/src/koni/background/handlers/Mobile.ts index 4411f77fd92..a1d9c267060 100644 --- a/packages/extension-base/src/koni/background/handlers/Mobile.ts +++ b/packages/extension-base/src/koni/background/handlers/Mobile.ts @@ -8,8 +8,11 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State' import { SWStorage } from '@subwallet/extension-base/storage'; import { isSupportWindow, listMerge } from '@subwallet/extension-base/utils'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { DexieExportJsonStructure } from 'dexie-export-import'; +const mobileHandlerLogger = createLogger('MobileHandler'); + export function isLocalStorageReset (): boolean { if (isSupportWindow && window?.localStorage) { return !window.localStorage.getItem('keyring:subwallet'); @@ -62,14 +65,14 @@ export default class Mobile { if (!isLocalStorageReset()) { swStorage.copy().then((data) => { this.lastRestoreData.storage = data; - }).catch(console.error); + }).catch((e) => mobileHandlerLogger.error('Error copying storage', e)); } (async () => { if (!(await isIndexedDBReset())) { this.lastRestoreData.indexedDB = await state.dbService.getExportJson(); } - })().catch(console.error); + })().catch((e) => mobileHandlerLogger.error('Error getting export JSON', e)); } public ping (): string { @@ -79,7 +82,7 @@ export default class Mobile { public initCronAndSubscription ( { cron: { activeServices: activeCronServices, intervalMap: cronIntervalMap }, subscription: { activeServices: activeSubscriptionServices } }: RequestInitCronAndSubscription): ActiveCronAndSubscriptionMap { - console.log('initCronAndSubscription'); + mobileHandlerLogger.debug('initCronAndSubscription'); return { subscription: { @@ -104,39 +107,39 @@ export default class Mobile { } public startCronAndSubscriptionServices ({ cronServices, subscriptionServices }: RequestCronAndSubscriptionAction): void { - console.log('startCronAndSubscriptionServices'); + mobileHandlerLogger.debug('startCronAndSubscriptionServices'); } public stopCronAndSubscriptionServices ({ cronServices, subscriptionServices }: RequestCronAndSubscriptionAction): void { - console.log('stopCronAndSubscriptionServices'); + mobileHandlerLogger.debug('stopCronAndSubscriptionServices'); } public restartCronAndSubscriptionServices ({ cronServices, subscriptionServices }: RequestCronAndSubscriptionAction): void { - console.log('restartCronAndSubscriptionServices'); + mobileHandlerLogger.debug('restartCronAndSubscriptionServices'); } public startCronServices (services: CronServiceType[]): void { - console.log('startCronServices'); + mobileHandlerLogger.debug('startCronServices'); } public stopCronServices (services: CronServiceType[]): void { - console.log('stopCronServices'); + mobileHandlerLogger.debug('stopCronServices'); } public restartCronServices (services: CronServiceType[]): void { - console.log('stopCronServices'); + mobileHandlerLogger.debug('stopCronServices'); } public startSubscriptionServices (services: SubscriptionServiceType[]): void { - console.log('startSubscriptionServices'); + mobileHandlerLogger.debug('startSubscriptionServices'); } public stopSubscriptionServices (services: SubscriptionServiceType[]): void { - console.log('stopSubscriptionServices'); + mobileHandlerLogger.debug('stopSubscriptionServices'); } public restartSubscriptionServices (services: SubscriptionServiceType[]): void { - console.log('restartSubscriptionServices'); + mobileHandlerLogger.debug('restartSubscriptionServices'); } private async _getLocalStorageExportData (): Promise { diff --git a/packages/extension-base/src/koni/background/handlers/State.ts b/packages/extension-base/src/koni/background/handlers/State.ts index e203c639359..009c33bdb60 100644 --- a/packages/extension-base/src/koni/background/handlers/State.ts +++ b/packages/extension-base/src/koni/background/handlers/State.ts @@ -64,6 +64,7 @@ import { BehaviorSubject, Subject } from 'rxjs'; import { JsonRpcResponse, ProviderInterface, ProviderInterfaceCallback } from '@polkadot/rpc-provider/types'; import { assert, logger as createLogger, noop } from '@polkadot/util'; import { Logger } from '@polkadot/util/types'; +import { createLogger as createExtensionLogger } from '@subwallet/extension-base/utils/logger'; import { isEthereumAddress } from '@polkadot/util-crypto'; import { KoniCron } from '../cron'; @@ -91,6 +92,8 @@ const generateDefaultCrowdloanMap = (): Record => { const DEFAULT_CURRENCY: CurrencyType = 'USD'; +const extensionLogger = createExtensionLogger('State'); + export default class KoniState { private injectedProviders = new Map(); private readonly providers: Providers; @@ -193,8 +196,8 @@ export default class KoniState { // Init state if (targetIsWeb) { this.init().then(() => { - this.wakeup(true).catch(console.error); - }).catch(console.error); + this.wakeup(true).catch((error) => extensionLogger.error('Error waking up state', error)); + }).catch((error) => extensionLogger.error('Error initializing state', error)); } } @@ -340,9 +343,9 @@ export default class KoniState { const mantaPayConfig = await this.chainService?.mantaPay?.getMantaPayFirstConfig(_DEFAULT_MANTA_ZK_CHAIN) as MantaPayConfig; if (mantaPayConfig && mantaPayConfig.enabled && !this.isMantaPayEnabled) { // only init the first login - console.debug('Initiating MantaPay for', mantaPayConfig.address); + extensionLogger.debug('Initiating MantaPay for', mantaPayConfig.address); await this.enableMantaPay(false, mantaPayConfig.address, password); - console.debug('Initiated MantaPay for', mantaPayConfig.address); + extensionLogger.debug('Initiated MantaPay for', mantaPayConfig.address); this.isMantaPayEnabled = true; this.eventService.emit('mantaPay.enable', mantaPayConfig.address); @@ -1229,7 +1232,7 @@ export default class KoniState { return await calculateGasFeeParams(web3Api, slug, false, false); } catch (e) { - console.error(e); + extensionLogger.error('Error calculating gas fee params', e); return null; } @@ -1825,7 +1828,7 @@ export default class KoniState { if (!migrationStatus || migrationStatus !== 'done') { if (!isManifestV3) { - this.migrateMV3LocalStorage(JSON.stringify(self.localStorage)).catch(console.error); + this.migrateMV3LocalStorage(JSON.stringify(self.localStorage)).catch((error) => extensionLogger.error('Error migrating MV3 localStorage', error)); } } } @@ -1856,11 +1859,11 @@ export default class KoniState { // Reload some services use SWStorage // wallet connect - this.walletConnectService.initClient().catch(console.error); + this.walletConnectService.initClient().catch((error) => extensionLogger.error('Error initializing wallet connect client', error)); return true; } catch (e) { - console.error(e); + extensionLogger.error('Error migrating MV3 localStorage', e); return false; } @@ -1878,10 +1881,10 @@ export default class KoniState { public onInstallOrUpdate (details: chrome.runtime.InstalledDetails) { // Open mv3 migration window if (details.reason === 'install') { - this.onMV3Install().catch(console.error); + this.onMV3Install().catch((error) => extensionLogger.error('Error on MV3 install', error)); } else if (details.reason === 'update') { - this.onMV3Update().catch(console.error); - this.storePreviousVersionData(details).catch(console.error); + this.onMV3Update().catch((error) => extensionLogger.error('Error on MV3 update', error)); + this.storePreviousVersionData(details).catch((error) => extensionLogger.error('Error storing previous version data', error)); } } @@ -1896,7 +1899,7 @@ export default class KoniState { openPopup(url) .then(noop) - .catch(console.error) + .catch((error) => extensionLogger.error('Error opening popup for remind export account', error)) .finally(() => subscription.unsubscribe()); } else { setTimeout(() => { @@ -1917,7 +1920,7 @@ export default class KoniState { return true; } catch (e) { - console.error(e); + extensionLogger.error('Error setting storage from WS', e); return false; } @@ -1927,7 +1930,7 @@ export default class KoniState { try { return await SWStorage.instance.getItem(key); } catch (e) { - console.error(e); + extensionLogger.error('Error getting storage from WS', e); return null; } @@ -1935,7 +1938,7 @@ export default class KoniState { public onCheckToRemindUser () { this.onHandleRemindExportAccount() - .catch(console.error); + .catch((error) => extensionLogger.error('Error checking to remind user', error)); } public onInstall () { @@ -2159,10 +2162,10 @@ export default class KoniState { const stores = this.dbService.stores; // Remove NFT - stores.nft.deleteNftByAddress([address]).catch(console.error); + stores.nft.deleteNftByAddress([address]).catch((error) => extensionLogger.error('Error deleting NFT by address', error)); // Remove Staking Data - stores.staking.removeAllByAddress(address).catch(console.error); + stores.staking.removeAllByAddress(address).catch((error) => extensionLogger.error('Error removing staking data by address', error)); }); } @@ -2375,7 +2378,7 @@ export default class KoniState { this.balanceService.setBalanceItem([balanceItem]); } }) - .catch(console.warn); + .catch((error) => extensionLogger.warn('Error getting Manta ZK balance', error)); } public subscribeMantaPayBalance () { @@ -2389,7 +2392,7 @@ export default class KoniState { interval = setInterval(this.getMantaZkBalance, MANTA_PAY_BALANCE_INTERVAL); } }) - .catch(console.warn); + .catch((error) => extensionLogger.warn('Error subscribing MantaPay balance', error)); return () => { interval && clearInterval(interval); diff --git a/packages/extension-base/src/koni/background/handlers/Tabs.ts b/packages/extension-base/src/koni/background/handlers/Tabs.ts index d5749567756..f749113eddc 100644 --- a/packages/extension-base/src/koni/background/handlers/Tabs.ts +++ b/packages/extension-base/src/koni/background/handlers/Tabs.ts @@ -41,6 +41,10 @@ import { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types'; import { hexStripPrefix, isArray, isNumber, u8aToHex } from '@polkadot/util'; import { isEthereumAddress } from '@polkadot/util-crypto'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const tabsHandlerLogger = createLogger('TabsHandler'); + interface AccountSub { subscription: Subscription; url: string; @@ -394,7 +398,7 @@ export default class KoniTabs { return cb(transformAccountsV2(accounts, false, authInfo, accountAuthTypes, true)); }) - .catch(console.error); + .catch((e) => tabsHandlerLogger.error('Error transforming accounts', e)); }), url }; @@ -474,7 +478,7 @@ export default class KoniTabs { } resolve(accounts); - }).catch(console.error); + }).catch((e) => tabsHandlerLogger.error('Error getting current account', e)); }); } @@ -508,7 +512,7 @@ export default class KoniTabs { if (web3?.currentProvider instanceof Web3.providers.WebsocketProvider) { if (!web3.currentProvider.connected) { - console.log(`${slug} is disconnected, trying to connect...`); + tabsHandlerLogger.debug(`${slug} is disconnected, trying to connect...`); this.#koniState.refreshWeb3Api(slug); let checkingNum = 0; @@ -516,15 +520,15 @@ export default class KoniTabs { checkingNum += 1; if ((web3.currentProvider as WebsocketProvider).connected) { - console.log(`${slug} is connected.`); + tabsHandlerLogger.debug(`${slug} is connected.`); resolve(true); } else { - console.log(`Connecting to network [${slug}]`); + tabsHandlerLogger.debug(`Connecting to network [${slug}]`); if (checkingNum < 10) { setTimeout(() => poll(resolve), 900); } else { - console.log(`Max retry, stop checking [${slug}]`); + tabsHandlerLogger.debug(`Max retry, stop checking [${slug}]`); resolve(false); } } @@ -915,7 +919,7 @@ export default class KoniTabs { const accountListSubscription = this.#koniState.keyringService.context.observable.currentAccount .subscribe(() => { - onCurrentAccountChanged().catch(console.error); + onCurrentAccountChanged().catch((e) => tabsHandlerLogger.error('Error on current account changed', e)); }); // Detect network chain @@ -944,7 +948,7 @@ export default class KoniTabs { const authUrlSubscription = this.#koniState.subscribeEvmChainChange() .subscribe((rs) => { - _onAuthChanged().catch(console.error); + _onAuthChanged().catch((e) => tabsHandlerLogger.error('Error on auth changed', e)); }); // Detect network connection @@ -960,8 +964,8 @@ export default class KoniTabs { isConnected = connecting; }) - .catch(console.error); - }).catch(console.error); + .catch((e) => tabsHandlerLogger.error('Error checking network connection', e)); + }).catch((e) => tabsHandlerLogger.error('Error in network check', e)); }; const networkCheckInterval = setInterval(networkCheck, CRON_GET_API_MAP_STATUS); @@ -1147,7 +1151,7 @@ export default class KoniTabs { if (e.code) { throw e; } else { - console.error(e); + tabsHandlerLogger.error('Error in performWeb3Method', e); throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, e?.toString()); } } @@ -1625,7 +1629,7 @@ export default class KoniTabs { if (e.code) { throw e; } else { - console.error(e); + tabsHandlerLogger.error('Error in performBitcoinMethod', e); throw new BitcoinProviderError(BitcoinProviderErrorType.INTERNAL_ERROR, e?.toString()); } } diff --git a/packages/extension-base/src/koni/background/handlers/index.ts b/packages/extension-base/src/koni/background/handlers/index.ts index f76503906bb..385311bc5bf 100644 --- a/packages/extension-base/src/koni/background/handlers/index.ts +++ b/packages/extension-base/src/koni/background/handlers/index.ts @@ -11,6 +11,10 @@ import KoniTabs from '@subwallet/extension-base/koni/background/handlers/Tabs'; import { assert } from '@polkadot/util'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const swHandlerLogger = createLogger('SWHandler'); + export class SWHandler { _state?: KoniState; _extensionHandler?: KoniExtension; @@ -77,8 +81,7 @@ export class SWHandler { port.postMessage({ id, response, sender: 'BACKGROUND' }); }) .catch((error: ProviderError): void => { - console.error(error); - console.log(`[err] ${source}:: ${error.message}`); + swHandlerLogger.error(`[err] ${source}`, error); // only send message back to port if it's still connected if (port) { diff --git a/packages/extension-base/src/koni/background/subscription.ts b/packages/extension-base/src/koni/background/subscription.ts index c42c0cf6c09..1a33524caf2 100644 --- a/packages/extension-base/src/koni/background/subscription.ts +++ b/packages/extension-base/src/koni/background/subscription.ts @@ -112,7 +112,7 @@ export class KoniSubscription { this.state.resetCrowdloanMap(address).then(() => { this.updateSubscription('crowdloan', this.initCrowdloanSubscription(addresses, substrateApiMap, onlyRunOnFirstTime)); - }).catch(console.error); + }).catch((e) => this.logger.error('Error resetting crowdloan map', e)); } initCrowdloanSubscription (addresses: string[], substrateApiMap: Record, onlyRunOnFirstTime?: boolean) { diff --git a/packages/extension-base/src/koni/background/utils.ts b/packages/extension-base/src/koni/background/utils.ts index 3a7566fe155..70d18cf2155 100644 --- a/packages/extension-base/src/koni/background/utils.ts +++ b/packages/extension-base/src/koni/background/utils.ts @@ -11,8 +11,12 @@ import { Metadata, TypeRegistry } from '@polkadot/types'; import { ChainProperties } from '@polkadot/types/interfaces'; import { Registry, SignerPayloadJSON } from '@polkadot/types/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + import KoniState from './handlers/State'; +const registryUtilsLogger = createLogger('RegistryUtils'); + export interface RegistrySource{ registry: Registry, specVersion: string | number, @@ -74,7 +78,7 @@ export async function setupApiRegistry (chainInfo: _ChainInfo | undefined, koniS specVersion: apiSpecVersion }; } catch (e) { - console.error('Error in setupApiRegistry:', e); + registryUtilsLogger.error('Error in setupApiRegistry', e); return null; } @@ -82,7 +86,7 @@ export async function setupApiRegistry (chainInfo: _ChainInfo | undefined, koniS export async function setupDatabaseRegistry (chainInfo: _ChainInfo | undefined, payload: SignerPayloadJSON, koniState: KoniState): Promise { if (!chainInfo) { - console.warn('setupDatabaseRegistry: Missing chainInfo'); + registryUtilsLogger.warn('setupDatabaseRegistry: Missing chainInfo'); return null; } @@ -91,7 +95,7 @@ export async function setupDatabaseRegistry (chainInfo: _ChainInfo | undefined, const metadata = await koniState.chainService.getMetadataByHash(payload.genesisHash) as MetadataItem; if (!metadata?.genesisHash) { - console.warn('setupDatabaseRegistry: Metadata not found or invalid for genesisHash:', payload.genesisHash); + registryUtilsLogger.warn('setupDatabaseRegistry: Metadata not found or invalid for genesisHash', payload.genesisHash); return null; } @@ -108,7 +112,7 @@ export async function setupDatabaseRegistry (chainInfo: _ChainInfo | undefined, specVersion: metadata.specVersion }; } catch (e) { - console.error('setupDatabaseRegistry: Error setting up database registry:', e); + registryUtilsLogger.error('setupDatabaseRegistry: Error setting up database registry', e); return null; } @@ -133,7 +137,7 @@ export function setupDappRegistry (payload: SignerPayloadJSON, koniState: KoniSt specVersion: metadata.specVersion }); } catch (e) { - console.error('setupDappRegistry: Error setting up DApp registry:', e); + registryUtilsLogger.error('setupDappRegistry: Error setting up DApp registry', e); resolve(null); } diff --git a/packages/extension-base/src/page/evm/index.ts b/packages/extension-base/src/page/evm/index.ts index e2aacf3caa4..f89f297ff47 100644 --- a/packages/extension-base/src/page/evm/index.ts +++ b/packages/extension-base/src/page/evm/index.ts @@ -8,6 +8,9 @@ import type { RequestArguments } from 'web3-core'; import SafeEventEmitter from '@metamask/safe-event-emitter'; import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const evmPageLogger = createLogger('EvmPage'); interface SendSyncJsonRpcRequest extends JsonRpcRequest { method: 'net_version'; @@ -57,7 +60,7 @@ export function createSubWalletEvmProvider (sendMessage: SendRequest, version: s emitter.emit(finalType, payload); } else { - console.warn('Can not handle event', type, payload); + evmPageLogger.warn('Can not handle event', type, payload); } }).then(() => { subscribeFlag = true; diff --git a/packages/extension-base/src/page/substrate/Accounts.ts b/packages/extension-base/src/page/substrate/Accounts.ts index 5bcda6cc2b1..aa583726781 100644 --- a/packages/extension-base/src/page/substrate/Accounts.ts +++ b/packages/extension-base/src/page/substrate/Accounts.ts @@ -4,8 +4,11 @@ import type { InjectedAccount, InjectedAccounts, Unsubcall } from '@subwallet/extension-inject/types'; import type { SendRequest } from '../types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + // External to class, this.# is not private enough (yet) let sendRequest: SendRequest; +const substrateAccountsLogger = createLogger('SubstrateAccounts'); export default class Accounts implements InjectedAccounts { constructor (_sendRequest: SendRequest) { @@ -23,11 +26,11 @@ export default class Accounts implements InjectedAccounts { .then((subId): void => { id = subId; }) - .catch(console.error); + .catch((e) => substrateAccountsLogger.error('Error subscribing to accounts', e)); return (): void => { id && sendRequest('pub(accounts.unsubscribe)', { id }) - .catch(console.error); + .catch((e) => substrateAccountsLogger.error('Error unsubscribing from accounts', e)); }; } } diff --git a/packages/extension-base/src/page/substrate/PostMessageProvider.ts b/packages/extension-base/src/page/substrate/PostMessageProvider.ts index b7901c4e4e5..543b04389e4 100644 --- a/packages/extension-base/src/page/substrate/PostMessageProvider.ts +++ b/packages/extension-base/src/page/substrate/PostMessageProvider.ts @@ -10,7 +10,10 @@ import EventEmitter from 'eventemitter3'; import { isUndefined, logger } from '@polkadot/util'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + const l = logger('PostMessageProvider'); +const postMessageProviderLogger = createLogger('PostMessageProvider'); type CallbackHandler = (error?: null | Error, value?: unknown) => void; @@ -64,7 +67,7 @@ export default class PostMessageProvider implements InjectedProvider { // eslint-disable-next-line @typescript-eslint/require-await public async connect (): Promise { // FIXME This should see if the extension's state's provider can disconnect - console.error('PostMessageProvider.disconnect() is not implemented.'); + postMessageProviderLogger.error('PostMessageProvider.connect() is not implemented.'); } /** @@ -73,7 +76,7 @@ export default class PostMessageProvider implements InjectedProvider { // eslint-disable-next-line @typescript-eslint/require-await public async disconnect (): Promise { // FIXME This should see if the extension's state's provider can disconnect - console.error('PostMessageProvider.disconnect() is not implemented.'); + postMessageProviderLogger.error('PostMessageProvider.disconnect() is not implemented.'); } /** diff --git a/packages/extension-base/src/page/substrate/index.ts b/packages/extension-base/src/page/substrate/index.ts index b1418ddfb7d..e3eefd56b98 100644 --- a/packages/extension-base/src/page/substrate/index.ts +++ b/packages/extension-base/src/page/substrate/index.ts @@ -9,6 +9,10 @@ import Metadata from './Metadata'; import PostMessageProvider from './PostMessageProvider'; import Signer from './Signer'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const substratePageLogger = createLogger('SubstratePage'); + export default class implements Injected { public readonly accounts: Accounts; @@ -26,7 +30,7 @@ export default class implements Injected { setInterval((): void => { sendRequest('pub(ping)', null).catch((): void => { - console.error('Extension unavailable, ping failed'); + substratePageLogger.error('Extension unavailable, ping failed'); }); }, 5_000 + Math.floor(Math.random() * 5_000)); } diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/bitcoin.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/bitcoin.ts index 8d32a050982..f4c754fe264 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/bitcoin.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/bitcoin.ts @@ -5,9 +5,12 @@ import { _AssetType } from '@subwallet/chain-list/types'; import { AddressBalanceResult, APIItemState, BitcoinBalanceMetadata } from '@subwallet/extension-base/background/KoniTypes'; import { BITCOIN_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants'; import { _BitcoinApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BalanceItem, SusbcribeBitcoinPalletBalance } from '@subwallet/extension-base/types'; import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; +const balanceSubscribeBitcoinLogger = createLogger('BalanceSubscribeBitcoin'); + function getDefaultBalanceResult (): AddressBalanceResult { return { balance: '0', @@ -41,7 +44,7 @@ async function getBitcoinBalance (bitcoinApi: _BitcoinApi, addresses: string[]) bitcoinBalanceMetadata: bitcoinBalanceMetadata }; } catch (error) { - console.log('Error while fetching Bitcoin balances', error); + balanceSubscribeBitcoinLogger.error('Error while fetching Bitcoin balances', error); return getDefaultBalanceResult(); } @@ -72,7 +75,7 @@ export function subscribeBitcoinBalance (params: SusbcribeBitcoinPalletBalance): }); }) .catch((e) => { - console.error('Error on get Bitcoin balance with token bitcoin', e); + balanceSubscribeBitcoinLogger.error('Error on get Bitcoin balance with token bitcoin', e); return addresses.map((address): BalanceItem => { return { @@ -87,7 +90,7 @@ export function subscribeBitcoinBalance (params: SusbcribeBitcoinPalletBalance): .then((items) => { callback(items); }) - .catch(console.error); + .catch((error) => balanceSubscribeBitcoinLogger.error('Error in Bitcoin balance subscription', error)); }; const interval = setInterval(getBalance, BITCOIN_REFRESH_BALANCE_INTERVAL); diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/index.ts index d159c0ea2a7..c4159c33c08 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/index.ts @@ -4,12 +4,15 @@ import { _AssetType } from '@subwallet/chain-list/types'; import { APIItemState } from '@subwallet/extension-base/background/KoniTypes'; import { ASTAR_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { CardanoBalanceItem } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types'; import { getCardanoAssetId } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/utils'; import { _CardanoApi } from '@subwallet/extension-base/services/chain-service/types'; import { BalanceItem, SusbcribeCardanoPalletBalance } from '@subwallet/extension-base/types'; import { filterAssetsByChainAndType, reformatAddress } from '@subwallet/extension-base/utils'; +const balanceSubscribeCardanoIndexLogger = createLogger('BalanceSubscribeCardano'); + async function getBalanceMap (addresses: string[], cardanoApi: _CardanoApi, isTestnet: boolean): Promise> { const addressBalanceMap: Record = {}; @@ -52,7 +55,7 @@ export function subscribeCardanoBalance (params: SusbcribeCardanoPalletBalance) callback(items); }); }) - .catch((e) => console.error('Error while fetching cardano balance', e)); + .catch((e) => balanceSubscribeCardanoIndexLogger.error('Error while fetching cardano balance', e)); } const interval = setInterval(getBalance, ASTAR_REFRESH_BALANCE_INTERVAL); diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/utils.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/utils.ts index 1b6c68ff016..4b45ce1e625 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/utils.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/cardano/utils.ts @@ -4,6 +4,9 @@ import { Transaction } from '@emurgo/cardano-serialization-lib-nodejs'; import { _ChainAsset } from '@subwallet/chain-list/types'; import { CardanoTxOutput } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const balanceSubscribeCardanoLogger = createLogger('BalanceSubscribeCardano'); export function getCardanoAssetId (chainAsset: _ChainAsset): string { return chainAsset.metadata?.cardanoId as string; @@ -46,7 +49,7 @@ export async function retryCardanoTxStatus (fn: () => Promise, options: } } - console.error('Cardano transaction timeout', lastError); // throw only last error, in case no successful result from fn() + balanceSubscribeCardanoLogger.error('Cardano transaction timeout', lastError); // throw only last error, in case no successful result from fn() return false; } diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/evm.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/evm.ts index e9fe5735f63..1eb21593413 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/evm.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/evm.ts @@ -8,12 +8,15 @@ import { getERC20Contract } from '@subwallet/extension-base/koni/api/contract-ha import { _BALANCE_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants'; import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BalanceItem, SubscribeEvmPalletBalance } from '@subwallet/extension-base/types'; import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; import { Contract } from 'web3-eth-contract'; import { BN } from '@polkadot/util'; +const balanceSubscribeEvmLogger = createLogger('BalanceSubscribeEvm'); + export function subscribeERC20Interval ({ addresses, assetMap, callback, chainInfo, evmApi }: SubscribeEvmPalletBalance): () => void { const chain = chainInfo.slug; let tokenList = filterAssetsByChainAndType(assetMap, chain, [_AssetType.ERC20]); @@ -39,7 +42,7 @@ export function subscribeERC20Interval ({ addresses, assetMap, callback, chainIn // eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access return await contract.methods.balanceOf(address).call(); } catch (e) { - console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e); + balanceSubscribeEvmLogger.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e); return '0'; } @@ -57,7 +60,7 @@ export function subscribeERC20Interval ({ addresses, assetMap, callback, chainIn callback(items); } catch (err) { - console.log(tokenInfo.slug, err); + balanceSubscribeEvmLogger.debug(tokenInfo.slug, err); } }); }; @@ -101,7 +104,7 @@ export function subscribeEVMBalance (params: SubscribeEvmPalletBalance) { }); }) .catch((e) => { - console.error(`Error on get native balance with token ${nativeTokenSlug}`, e); + balanceSubscribeEvmLogger.error(`Error on get native balance with token ${nativeTokenSlug}`, e); return addresses.map((address): BalanceItem => { return { @@ -116,7 +119,7 @@ export function subscribeEVMBalance (params: SubscribeEvmPalletBalance) { .then((items) => { callback(items); }) - .catch(console.error) + .catch((error) => balanceSubscribeEvmLogger.error('Error in EVM balance subscription', error)) ; } diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts index ce1cac164c3..f9bf0e1cba6 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/index.ts @@ -10,10 +10,13 @@ import { _isPureBitcoinChain, _isPureCardanoChain, _isPureEvmChain, _isPureTonCh import { BalanceItem } from '@subwallet/extension-base/types'; import { filterAddressByChainInfo, filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { subscribeTonBalance } from './ton/ton'; import { subscribeEVMBalance } from './evm'; import { subscribeSubstrateBalance } from './substrate'; +const balanceSubscribeLogger = createLogger('BalanceSubscribe'); + const handleUnsupportedOrPendingAddresses = ( addresses: string[], chainSlug: string, @@ -150,7 +153,7 @@ export function subscribeBalance ( unsubList.forEach((subProm) => { subProm.then((unsub) => { unsub && unsub(); - }).catch(console.error); + }).catch((error) => balanceSubscribeLogger.error('Error in balance subscription', error)); }); }; } diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/equilibrium.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/equilibrium.ts index a37295224fe..24b1c20df39 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/equilibrium.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/equilibrium.ts @@ -4,6 +4,7 @@ import { SignedBalance } from '@equilab/api/genshiro/interfaces'; import { _AssetType } from '@subwallet/chain-list/types'; import { APIItemState } from '@subwallet/extension-base/background/KoniTypes'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { _getTokenOnChainAssetId } from '@subwallet/extension-base/services/chain-service/utils'; import { BalanceItem, SubscribeSubstratePalletBalance } from '@subwallet/extension-base/types'; import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; @@ -11,6 +12,8 @@ import BigN from 'bignumber.js'; import { BN, BN_ZERO } from '@polkadot/util'; +const balanceSubscribeEquilibriumLogger = createLogger('BalanceSubscribeEquilibrium'); + type EqBalanceItem = [number, { positive: number }]; type EqBalanceV0 = { v0: { @@ -100,7 +103,7 @@ export const subscribeEqBalanceAccountPallet = async ({ addresses, assetMap, cal return unsub; } catch (err) { - console.warn(err); + balanceSubscribeEquilibriumLogger.warn('Error in equilibrium balance subscription', err); const items: BalanceItem[] = addresses.map((address) => { return { @@ -122,7 +125,7 @@ export const subscribeEqBalanceAccountPallet = async ({ addresses, assetMap, cal unsubList.forEach((subProm) => { subProm.then((unsub) => { unsub && unsub(); - }).catch(console.error); + }).catch((error) => balanceSubscribeEquilibriumLogger.error('Error in equilibrium balance subscription', error)); }); }; }; diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/gear.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/gear.ts index f3ba1362948..0b380b2d1f8 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/gear.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/gear.ts @@ -5,10 +5,13 @@ import { GearApi } from '@gear-js/api'; import { _AssetType } from '@subwallet/chain-list/types'; import { APIItemState } from '@subwallet/extension-base/background/KoniTypes'; import { SUB_TOKEN_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; import { BalanceItem, SubscribeSubstratePalletBalance } from '@subwallet/extension-base/types'; import { filterAssetsByChainAndType, getGRC20ContractPromise, getVFTContractPromise, GRC20, VFT } from '@subwallet/extension-base/utils'; +const balanceSubscribeGearLogger = createLogger('BalanceSubscribeGear'); + import { noop, u8aToHex } from '@polkadot/util'; import { decodeAddress } from '@polkadot/util-crypto'; @@ -20,7 +23,7 @@ export const subscribeGRC20Balance = ({ addresses, const apiPromise = substrateApi.api; if (!(apiPromise instanceof GearApi)) { - console.warn('Cannot subscribe GRC20 balance without GearApi instance'); + balanceSubscribeGearLogger.warn('Cannot subscribe GRC20 balance without GearApi instance'); return noop; } @@ -50,7 +53,7 @@ export const subscribeGRC20Balance = ({ addresses, state: APIItemState.READY }; } catch (err) { - console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, err); + balanceSubscribeGearLogger.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, err); return { address: address, @@ -64,7 +67,7 @@ export const subscribeGRC20Balance = ({ addresses, callback(balances); } catch (err) { - console.warn(tokenInfo.slug, err); // TODO: error createType + balanceSubscribeGearLogger.warn(`Error for token ${tokenInfo.slug}`, err); // TODO: error createType } }); }; @@ -86,7 +89,7 @@ export const subscribeVftBalance = ({ addresses, const apiPromise = substrateApi.api; if (!(apiPromise instanceof GearApi)) { - console.warn('Cannot subscribe VFT balance without GearApi instance'); + balanceSubscribeGearLogger.warn('Cannot subscribe VFT balance without GearApi instance'); return noop; } @@ -116,7 +119,7 @@ export const subscribeVftBalance = ({ addresses, state: APIItemState.READY }; } catch (err) { - console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, err); + balanceSubscribeGearLogger.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, err); return { address: address, @@ -130,7 +133,7 @@ export const subscribeVftBalance = ({ addresses, callback(balances); } catch (err) { - console.warn(tokenInfo.slug, err); // TODO: error createType + balanceSubscribeGearLogger.warn(`Error for token ${tokenInfo.slug}`, err); // TODO: error createType } }); }; diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/index.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/index.ts index da2fb7c8b75..8a144e8942c 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/index.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/substrate/index.ts @@ -25,11 +25,14 @@ import { timer } from 'rxjs'; import { ContractPromise } from '@polkadot/api-contract'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { subscribeERC20Interval } from '../evm'; import { subscribeEquilibriumTokenBalance } from './equilibrium'; import { subscribeGRC20Balance, subscribeVftBalance } from './gear'; import { buildLockedDetails, getSpecialStakingBalances } from './utils'; +const balanceSubscribeSubstrateLogger = createLogger('BalanceSubscribeSubstrate'); + export const subscribeSubstrateBalance = async (addresses: string[], chainInfo: _ChainInfo, assetMap: Record, substrateApi: _SubstrateApi, evmApi: _EvmApi, callback: (rs: BalanceItem[]) => void, extrinsicType?: ExtrinsicType) => { let unsubNativeToken: () => void; let unsubLocalToken: () => void; @@ -108,7 +111,7 @@ export const subscribeSubstrateBalance = async (addresses: string[], chainInfo: unsubVftToken = subscribeVftBalance(substrateParams); } } catch (err) { - console.warn(err); + balanceSubscribeSubstrateLogger.warn('Error in substrate balance subscription', err); } return () => { @@ -323,7 +326,7 @@ const subscribeForeignAssetBalance = async ({ addresses, assetMap, callback, cha }); } } catch (err) { - console.warn(err); + balanceSubscribeSubstrateLogger.warn('Error in substrate balance subscription', err); } return undefined; @@ -376,7 +379,7 @@ const subscribePSP22Balance = ({ addresses, assetMap, callback, chainInfo, subst state: APIItemState.READY }; } catch (err) { - console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, err); + balanceSubscribeSubstrateLogger.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, err); return { address: address, @@ -390,7 +393,7 @@ const subscribePSP22Balance = ({ addresses, assetMap, callback, chainInfo, subst callback(balances); } catch (err) { - console.warn(tokenInfo.slug, err); // TODO: error createType + balanceSubscribeSubstrateLogger.warn(`Error for token ${tokenInfo.slug}`, err); // TODO: error createType } }); }; @@ -419,7 +422,7 @@ const subscribeTokensAccountsPallet = async ({ addresses, assetMap, callback, ch callback(gigaTokenBalances); }; - getGigaTokenBalance().catch(console.error); + getGigaTokenBalance().catch((error) => balanceSubscribeSubstrateLogger.error('Error getting Giga token balance', error)); }); } @@ -452,7 +455,7 @@ const subscribeTokensAccountsPallet = async ({ addresses, assetMap, callback, ch callback(items); }); } catch (err) { - console.warn(err); + balanceSubscribeSubstrateLogger.warn('Error in substrate balance subscription', err); } return undefined; @@ -524,7 +527,7 @@ const subscribeAssetsAccountPallet = async ({ addresses, assetMap, callback, cha callback(items); }); } catch (err) { - console.warn(err); + balanceSubscribeSubstrateLogger.warn('Error in substrate balance subscription', err); } return undefined; @@ -573,7 +576,7 @@ const subscribeOrmlTokensPallet = async ({ addresses, assetMap, callback, chainI callback(items); }); } catch (err) { - console.warn(err); + balanceSubscribeSubstrateLogger.warn('Error in substrate balance subscription', err); return undefined; } @@ -635,10 +638,10 @@ const subscribeSubnetAlphaPallet = async ({ addresses, assetMap, callback, chain } }; - getTokenBalances().catch(console.error); + getTokenBalances().catch((error) => balanceSubscribeSubstrateLogger.error('Error getting token balances', error)); const interval = setInterval(() => { - getTokenBalances().catch(console.error); + getTokenBalances().catch((error) => balanceSubscribeSubstrateLogger.error('Error getting token balances', error)); }, SUB_TOKEN_REFRESH_BALANCE_INTERVAL); return () => { diff --git a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts index 08ce13b9cb1..674994fc092 100644 --- a/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts +++ b/packages/extension-base/src/services/balance-service/helpers/subscribe/ton/ton.ts @@ -7,11 +7,14 @@ import { ASTAR_REFRESH_BALANCE_INTERVAL, SUB_TOKEN_REFRESH_BALANCE_INTERVAL } fr import { getJettonMasterContract, getJettonWalletContract } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils'; import { _TonApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BalanceItem, SubscribeTonPalletBalance } from '@subwallet/extension-base/types'; import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils'; import { Address } from '@ton/core'; import { JettonMaster, OpenedContract } from '@ton/ton'; +const balanceSubscribeTonLogger = createLogger('BalanceSubscribeTon'); + export function subscribeJettonBalanceInterval ({ addresses, assetMap, callback, chainInfo, tonApi }: SubscribeTonPalletBalance): () => void { const chain = chainInfo.slug; const tokenList = filterAssetsByChainAndType(assetMap, chain, [_AssetType.TEP74]); @@ -31,7 +34,7 @@ export function subscribeJettonBalanceInterval ({ addresses, assetMap, callback, return await jettonWalletContract.getBalance(); } catch (e) { - console.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e); + balanceSubscribeTonLogger.error(`Error on get balance of account ${address} for token ${tokenInfo.slug}`, e); return BigInt(0); } @@ -49,7 +52,7 @@ export function subscribeJettonBalanceInterval ({ addresses, assetMap, callback, callback(items); } catch (err) { - console.log(tokenInfo.slug, err); + balanceSubscribeTonLogger.debug(tokenInfo.slug, err); } }); }; @@ -95,7 +98,7 @@ export function subscribeTonBalance (params: SubscribeTonPalletBalance) { }); }) .catch((e) => { - console.error(`Error on get native balance with token ${nativeTokenSlug}`, e); + balanceSubscribeTonLogger.error(`Error on get native balance with token ${nativeTokenSlug}`, e); return addresses.map((address): BalanceItem => { return { @@ -108,7 +111,7 @@ export function subscribeTonBalance (params: SubscribeTonPalletBalance) { }); }) .then((items) => callback(items)) - .catch(console.error); + .catch((error) => balanceSubscribeTonLogger.error('Error in TON balance subscription', error)); } getBalance(); diff --git a/packages/extension-base/src/services/balance-service/index.ts b/packages/extension-base/src/services/balance-service/index.ts index 1fb41c269b4..62d968cc312 100644 --- a/packages/extension-base/src/services/balance-service/index.ts +++ b/packages/extension-base/src/services/balance-service/index.ts @@ -23,8 +23,11 @@ import { t } from 'i18next'; import { BehaviorSubject } from 'rxjs'; import { noop } from '@polkadot/util'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { _BALANCE_CHAIN_GROUP } from '../chain-service/constants'; + +const balanceServiceLogger = createLogger('BalanceService'); import { CreateXcmExtrinsicProps } from './transfer/xcm'; import { _isAcrossChainBridge, getAcrossQuote } from './transfer/xcm/acrossBridge'; import { BalanceMapImpl } from './BalanceMapImpl'; @@ -179,7 +182,7 @@ export class BalanceService implements StoppableServiceInterface { if (needReload) { addLazy('reloadBalanceByEvents', () => { if (!this.isReload && this.isStarted) { - this.runSubscribeBalances().catch(console.error); + this.runSubscribeBalances().catch((error) => balanceServiceLogger.error('Error running subscribe balances', error)); } }, lazyTime, undefined, true); } @@ -425,7 +428,7 @@ export class BalanceService implements StoppableServiceInterface { * Store balance map to db * */ private updateBalanceStore (items: BalanceItem[]) { - this.state.dbService.updateBulkBalanceStore(items).catch(console.warn); + this.state.dbService.updateBulkBalanceStore(items).catch((error) => balanceServiceLogger.warn('Error updating bulk balance store', error)); } /** @@ -487,7 +490,7 @@ export class BalanceService implements StoppableServiceInterface { const chainInfoMap = this.state.chainService.getChainInfoMap(); if (!chainInfoMap[chain]) { - console.warn(`Chain ${chain} is not supported`); + balanceServiceLogger.warn(`Chain ${chain} is not supported`); return; } @@ -550,7 +553,7 @@ export class BalanceService implements StoppableServiceInterface { if (typeValid) { return this.state.subscanService.getMultiChainBalance(address) .catch((e) => { - console.error(e); + balanceServiceLogger.error('Error in balance service operation', e); return null; }); @@ -566,7 +569,7 @@ export class BalanceService implements StoppableServiceInterface { if (typeValid) { return subwalletApiSdk.balanceDetectionApi.getSwEvmTokenBalance(address) .catch((e) => { - console.error(e); + balanceServiceLogger.error('Error in balance service operation', e); return null; }); @@ -758,7 +761,7 @@ export class BalanceService implements StoppableServiceInterface { const evmPromiseList = addresses.map((address) => { return subwalletApiSdk.balanceDetectionApi.getSwEvmTokenBalance(address) .catch((e) => { - console.error(e); + balanceServiceLogger.error('Error detecting EVM balance token', e); return null; }); @@ -795,7 +798,7 @@ export class BalanceService implements StoppableServiceInterface { const promiseList = addresses.map((address) => { return this.state.subscanService.getMultiChainBalance(address) .catch((e) => { - console.error(e); + balanceServiceLogger.error('Error detecting substrate balance token', e); return null; }); @@ -907,7 +910,7 @@ export class BalanceService implements StoppableServiceInterface { this.state.chainService.setAssetSettings(updatedSettings); } catch (e) { - console.error(e); + balanceServiceLogger.error('Error updating asset settings', e); } } diff --git a/packages/extension-base/src/services/balance-service/transfer/bitcoin-transfer.ts b/packages/extension-base/src/services/balance-service/transfer/bitcoin-transfer.ts index bb540282bc3..f6bf743195e 100644 --- a/packages/extension-base/src/services/balance-service/transfer/bitcoin-transfer.ts +++ b/packages/extension-base/src/services/balance-service/transfer/bitcoin-transfer.ts @@ -4,6 +4,7 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { _BITCOIN_CHAIN_SLUG, _BITCOIN_NAME, _BITCOIN_TESTNET_NAME } from '@subwallet/extension-base/services/chain-service/constants'; import { _BitcoinApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BitcoinFeeInfo, BitcoinFeeRate, FeeInfo, TransactionFee } from '@subwallet/extension-base/types'; import { combineBitcoinFee, determineUtxosForSpend, determineUtxosForSpendAll, getTransferableBitcoinUtxos } from '@subwallet/extension-base/utils'; import { BitcoinAddressType } from '@subwallet/keyring/types'; @@ -12,6 +13,8 @@ import { keyring } from '@subwallet/ui-keyring'; import BigN from 'bignumber.js'; import { Network, Psbt } from 'bitcoinjs-lib'; +const bitcoinTransferLogger = createLogger('BitcoinTransfer'); + export interface TransferBitcoinProps extends TransactionFee { bitcoinApi: _BitcoinApi; chain: string; @@ -108,7 +111,7 @@ export async function createBitcoinTransaction (params: TransferBitcoinProps): P throw e; } - console.warn('Failed to create Bitcoin transaction:', e); + bitcoinTransferLogger.warn('Failed to create Bitcoin transaction', e); throw new Error(`You don’t have enough BTC (${convertChainToSymbol(chain)}) for the transaction. Lower your BTC amount and try again`); } } diff --git a/packages/extension-base/src/services/balance-service/transfer/cardano-transfer.ts b/packages/extension-base/src/services/balance-service/transfer/cardano-transfer.ts index 34a22991d4a..36e30c5e457 100644 --- a/packages/extension-base/src/services/balance-service/transfer/cardano-transfer.ts +++ b/packages/extension-base/src/services/balance-service/transfer/cardano-transfer.ts @@ -7,9 +7,12 @@ import { ErrorValidation } from '@subwallet/extension-base/background/KoniTypes' import { CardanoTxJson, CardanoTxOutput } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/types'; import { CardanoAssetMetadata, getAdaBelongUtxo, getCardanoTxFee, splitCardanoId } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/utils'; import { _CardanoApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { toUnit } from '@subwallet/extension-base/utils'; import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk'; +const cardanoTransferLogger = createLogger('CardanoTransfer'); + export interface CardanoTransactionConfigProps { tokenInfo: _ChainAsset; nativeTokenInfo: _ChainAsset; @@ -86,7 +89,7 @@ export async function createCardanoTransaction (params: CardanoTransactionConfig throw new Error(`Insufficient ${nativeTokenSymbol} balance to perform transaction. Top up ${nativeTokenSymbol} and try again`); } - console.error(`Transaction is not built successfully: ${errorMessage}`); + cardanoTransferLogger.error(`Transaction is not built successfully: ${errorMessage}`); throw new Error('Unable to perform this transaction at the moment. Try again later'); } @@ -94,7 +97,7 @@ export async function createCardanoTransaction (params: CardanoTransactionConfig throw new Error('Build cardano payload failed!'); } - console.log('Build cardano payload successfully!', payload); + cardanoTransferLogger.debug('Build cardano payload successfully', payload); validatePayload(payload, params); diff --git a/packages/extension-base/src/services/balance-service/transfer/smart-contract.ts b/packages/extension-base/src/services/balance-service/transfer/smart-contract.ts index d437d3fcbd0..0a352b23c46 100644 --- a/packages/extension-base/src/services/balance-service/transfer/smart-contract.ts +++ b/packages/extension-base/src/services/balance-service/transfer/smart-contract.ts @@ -7,6 +7,7 @@ import { getPSP34ContractPromise } from '@subwallet/extension-base/koni/api/cont import { getWasmContractGasLimit } from '@subwallet/extension-base/koni/api/contract-handler/wasm/utils'; import { EVM_REFORMAT_DECIMALS } from '@subwallet/extension-base/services/chain-service/constants'; import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { EvmEIP1559FeeOption, EvmFeeInfo, FeeInfo, TransactionFee } from '@subwallet/extension-base/types'; import { combineEthFee } from '@subwallet/extension-base/utils'; import BigN from 'bignumber.js'; @@ -14,6 +15,8 @@ import { t } from 'i18next'; import { TransactionConfig } from 'web3-core'; import { ContractSendMethod } from 'web3-eth-contract'; +const smartContractLogger = createLogger('SmartContractTransfer'); + interface TransferEvmProps extends TransactionFee { chain: string; from: string; @@ -74,7 +77,7 @@ export async function getEVMTransactionObject (props: TransferEvmProps): Promise gasLimit = gasSettingsForEWC.gasLimit; } else { const gasEstimate = await evmApi.api.eth.estimateGas(transactionObject).catch((e: Error) => { - console.log('Cannot estimate fee with native transfer on', chain, e); + smartContractLogger.warn('Cannot estimate fee with native transfer on', chain, e); if (fallbackFee) { errorOnEstimateFee = e.message; @@ -163,7 +166,7 @@ export async function getERC20TransactionObject (props: TransferERC20Props): Pro // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access gasLimit = await (erc20Contract.methods.transfer(to, transferValue) as ContractSendMethod).estimateGas({ from }) .catch((e: Error) => { - console.log('Cannot estimate fee with token contract', assetAddress, chain, e); + smartContractLogger.warn('Cannot estimate fee with token contract', assetAddress, chain, e); if (fallbackFee) { errorOnEstimateFee = e.message; @@ -269,7 +272,7 @@ export async function getPSP34TransferExtrinsic (substrateApi: _SubstrateApi, se // @ts-ignore return contractPromise.tx['psp34::transfer']({ gasLimit }, recipientAddress, onChainOption, {}); } catch (e) { - console.debug(e); + smartContractLogger.debug('Error in smart contract transfer', e); return null; } diff --git a/packages/extension-base/src/services/balance-service/transfer/token.ts b/packages/extension-base/src/services/balance-service/transfer/token.ts index c38a59145cc..6e41460fd83 100644 --- a/packages/extension-base/src/services/balance-service/transfer/token.ts +++ b/packages/extension-base/src/services/balance-service/transfer/token.ts @@ -11,6 +11,7 @@ import { _EvmApi, _SubstrateApi, _TonApi } from '@subwallet/extension-base/servi import { _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo, _getXcmAssetMultilocation, _isBridgedToken, _isChainEvmCompatible, _isChainTonCompatible, _isGigaToken, _isNativeToken, _isTokenGearSmartContract, _isTokenTransferredByEvm, _isTokenTransferredByTon, _isTokenWasmSmartContract } from '@subwallet/extension-base/services/chain-service/utils'; import { TaoStakeInfo } from '@subwallet/extension-base/services/earning-service/handlers/native-staking/tao'; import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { combineEthFee, getGRC20ContractPromise, getVFTContractPromise } from '@subwallet/extension-base/utils'; import { keyring } from '@subwallet/ui-keyring'; import { internal } from '@ton/core'; @@ -19,6 +20,8 @@ import BigN from 'bignumber.js'; import { TransactionConfig } from 'web3-core'; import { SubmittableExtrinsic } from '@polkadot/api/promise/types'; + +const tokenTransferLogger = createLogger('TokenTransfer'); import { BN, u8aToHex } from '@polkadot/util'; import { decodeAddress } from '@polkadot/util-crypto'; @@ -192,7 +195,7 @@ export const getTransferMockTxFee = async (address: string, chainInfo: _ChainInf return estimatedFee; } catch (e) { - console.error('error mocking tx fee', e); + tokenTransferLogger.error('error mocking tx fee', e); return new BigN(0); } diff --git a/packages/extension-base/src/services/balance-service/transfer/xcm/acrossBridge/index.ts b/packages/extension-base/src/services/balance-service/transfer/xcm/acrossBridge/index.ts index 84ac797bfbf..28be4fe4187 100644 --- a/packages/extension-base/src/services/balance-service/transfer/xcm/acrossBridge/index.ts +++ b/packages/extension-base/src/services/balance-service/transfer/xcm/acrossBridge/index.ts @@ -6,12 +6,15 @@ import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; import { _isAcrossBridgeXcm } from '@subwallet/extension-base/core/substrate/xcm-parser'; import { _getAssetDecimals, _getContractAddressOfToken, _getEvmChainId } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BasicTxErrorType } from '@subwallet/extension-base/types'; import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk'; import BigN from 'bignumber.js'; import { CreateXcmExtrinsicProps } from '..'; +const acrossBridgeLogger = createLogger('AcrossBridge'); + // Across Bridge const acrossPairsMap = new Map([ [COMMON_CHAIN_SLUGS.ETHEREUM, new Set(['optimism', 'base_mainnet', 'arbitrum_one'])], @@ -125,7 +128,7 @@ export const getAcrossSendingValue = async (originChain: _ChainInfo, originToken return sendingValue; } catch (error) { - console.error('Across Bridge error:', error); + acrossBridgeLogger.error('Across Bridge error', error); // fallback in case fetch API fail const defaultSendingAmount = isTestnet ? 0.0037 : 1; diff --git a/packages/extension-base/src/services/balance-service/transfer/xcm/availBridge.ts b/packages/extension-base/src/services/balance-service/transfer/xcm/availBridge.ts index 824b24d5b80..4e89f931b60 100644 --- a/packages/extension-base/src/services/balance-service/transfer/xcm/availBridge.ts +++ b/packages/extension-base/src/services/balance-service/transfer/xcm/availBridge.ts @@ -8,6 +8,7 @@ import { _AVAIL_BRIDGE_GATEWAY_ABI, _AVAIL_TEST_BRIDGE_GATEWAY_ABI, getAvailBrid import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { _NotificationInfo, ClaimAvailBridgeNotificationMetadata } from '@subwallet/extension-base/services/inapp-notification-service/interfaces'; import { AVAIL_BRIDGE_API } from '@subwallet/extension-base/services/inapp-notification-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { EvmEIP1559FeeOption, EvmFeeInfo, FeeCustom, FeeInfo, FeeOption } from '@subwallet/extension-base/types'; import { combineEthFee } from '@subwallet/extension-base/utils'; import { decodeAddress } from '@subwallet/keyring'; @@ -17,6 +18,8 @@ import { ContractSendMethod } from 'web3-eth-contract'; import { u8aToHex } from '@polkadot/util'; +const availBridgeLogger = createLogger('AvailBridge'); + export const AvailBridgeConfig = { ASSET_ID: '0x0000000000000000000000000000000000000000000000000000000000000000', ETHEREUM_DOMAIN: 2, // todo: check if these config can change later @@ -120,7 +123,7 @@ async function getLatestEthHeadSlot (chainSlug: string) { return response.slot; } catch (e) { - console.error(e); + availBridgeLogger.error('Error in AvailBridge operation', e); throw e; } } @@ -133,7 +136,7 @@ async function getLatestBlockHash (chainSlug: string, slot: number) { return response.blockHash; } catch (e) { - console.error(e); + availBridgeLogger.error('Error in AvailBridge operation', e); throw e; } } @@ -145,7 +148,7 @@ async function getClaimProofOnAvail (chainSlug: string, blockHash: string, messa return await rawResponse.json() as { accountProof: PrefixedHexString[], storageProof: PrefixedHexString[] }; } catch (e) { - console.error(e); + availBridgeLogger.error('Error in AvailBridge operation', e); throw e; } } @@ -157,7 +160,7 @@ async function getClaimProofOnEthereum (chainSlug: string, blockHash: string, tr return await rawResponse.json() as merkleProof; } catch (e) { - console.error(e); + availBridgeLogger.error('Error in AvailBridge operation', e); throw e; } } diff --git a/packages/extension-base/src/services/balance-service/transfer/xcm/index.ts b/packages/extension-base/src/services/balance-service/transfer/xcm/index.ts index 8cc3f8134ed..3c908310d09 100644 --- a/packages/extension-base/src/services/balance-service/transfer/xcm/index.ts +++ b/packages/extension-base/src/services/balance-service/transfer/xcm/index.ts @@ -8,6 +8,7 @@ import { _createPolygonBridgeL1toL2Extrinsic, _createPolygonBridgeL2toL1Extrinsi import { getSnowBridgeEvmTransfer } from '@subwallet/extension-base/services/balance-service/transfer/xcm/snowBridge'; import { buildXcm, dryRunPreviewXcm, dryRunXcm, estimateXcmFee, isChainNotSupportDryRun, isChainNotSupportPolkadotApi } from '@subwallet/extension-base/services/balance-service/transfer/xcm/utils'; import { _EvmApi, _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { EvmEIP1559FeeOption, EvmFeeInfo, FeeInfo, TransactionFee } from '@subwallet/extension-base/types'; import { combineEthFee } from '@subwallet/extension-base/utils'; import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk'; @@ -17,6 +18,8 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'; import { _createPosBridgeL1toL2Extrinsic, _createPosBridgeL2toL1Extrinsic } from './posBridge'; +const xcmTransferLogger = createLogger('XcmTransfer'); + export type CreateXcmExtrinsicProps = { destinationChain: _ChainInfo; destinationTokenInfo: _ChainAsset; @@ -128,7 +131,7 @@ export const createXcmExtrinsicV2 = async (request: CreateXcmExtrinsicProps): Pr try { return await buildXcm(request); } catch (e) { - console.log('createXcmExtrinsicV2 error: ', e); + xcmTransferLogger.error('createXcmExtrinsicV2 error', e); return undefined; } diff --git a/packages/extension-base/src/services/balance-service/transfer/xcm/posBridge.ts b/packages/extension-base/src/services/balance-service/transfer/xcm/posBridge.ts index 273ee52735c..a84124d2f46 100644 --- a/packages/extension-base/src/services/balance-service/transfer/xcm/posBridge.ts +++ b/packages/extension-base/src/services/balance-service/transfer/xcm/posBridge.ts @@ -8,11 +8,14 @@ import { _POS_BRIDGE_ABI, _POS_BRIDGE_L2_ABI, getPosL1BridgeContract, getPosL2Br import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { _NotificationInfo, ClaimPolygonBridgeNotificationMetadata } from '@subwallet/extension-base/services/inapp-notification-service/interfaces'; import { fetchPolygonBridgeTransactions } from '@subwallet/extension-base/services/inapp-notification-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BasicTxErrorType, EvmEIP1559FeeOption, EvmFeeInfo, FeeCustom, FeeInfo, FeeOption } from '@subwallet/extension-base/types'; import { combineEthFee } from '@subwallet/extension-base/utils'; import { TransactionConfig } from 'web3-core'; import { ContractSendMethod } from 'web3-eth-contract'; +const posBridgeLogger = createLogger('PosBridge'); + interface inputData { error?: string message: string; @@ -113,7 +116,7 @@ export async function getClaimPosBridge (chainSlug: string, notification: _Notif throw new Error(`${inputData.message}. Please try again later.`); } } catch (err) { - console.error('Error:', err); + posBridgeLogger.error('Error in PosBridge operation', err); throw new Error(BasicTxErrorType.INTERNAL_ERROR); } @@ -151,7 +154,7 @@ export async function isClaimedPosBridge (id: string, address: string, isTestnet return !isIdClaimable; } } catch (err) { - console.error('Error:', err); + posBridgeLogger.error('Error in PosBridge operation', err); } return false; diff --git a/packages/extension-base/src/services/balance-service/transfer/xcm/snowBridge.ts b/packages/extension-base/src/services/balance-service/transfer/xcm/snowBridge.ts index 82381cae0c7..bd40c66a95a 100644 --- a/packages/extension-base/src/services/balance-service/transfer/xcm/snowBridge.ts +++ b/packages/extension-base/src/services/balance-service/transfer/xcm/snowBridge.ts @@ -8,6 +8,7 @@ import { getWeb3Contract } from '@subwallet/extension-base/koni/api/contract-han import { _SNOWBRIDGE_GATEWAY_ABI, getSnowBridgeGatewayContract } from '@subwallet/extension-base/koni/api/contract-handler/utils'; import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken, _getSubstrateParaId, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { EvmEIP1559FeeOption, EvmFeeInfo, FeeCustom, FeeInfo, FeeOption } from '@subwallet/extension-base/types'; import { combineEthFee } from '@subwallet/extension-base/utils'; import { TransactionConfig } from 'web3-core'; @@ -15,6 +16,8 @@ import { TransactionConfig } from 'web3-core'; import { u8aToHex } from '@polkadot/util'; import { decodeAddress } from '@polkadot/util-crypto'; +const snowBridgeLogger = createLogger('SnowBridge'); + export async function getSnowBridgeEvmTransfer (tokenInfo: _ChainAsset, originChainInfo: _ChainInfo, destinationChainInfo: _ChainInfo, sender: string, recipientAddress: string, value: string, evmApi: _EvmApi, _feeInfo: FeeInfo, feeCustom?: FeeCustom, feeOption?: FeeOption): Promise { const snowBridgeContractAddress = getSnowBridgeGatewayContract(originChainInfo.slug); const snowBridgeContract = getWeb3Contract(snowBridgeContractAddress, evmApi, _SNOWBRIDGE_GATEWAY_ABI); @@ -40,7 +43,7 @@ export async function getSnowBridgeEvmTransfer (tokenInfo: _ChainAsset, originCh destinationChainParaId ); - console.log('deliveryFee', deliveryFee); + snowBridgeLogger.debug('deliveryFee', deliveryFee); totalFee = deliveryFee.totalFeeInWei.toString(); destinationFee = (deliveryFee.destinationDeliveryFeeDOT + deliveryFee.destinationExecutionFeeDOT).toString(); @@ -48,7 +51,7 @@ export async function getSnowBridgeEvmTransfer (tokenInfo: _ChainAsset, originCh // Clean up all open connections await context.destroyContext(); } catch (error) { - console.error('Cannot get snow-bridge delivery fees with error:', error); + snowBridgeLogger.error('Cannot get snow-bridge delivery fees with error', error); totalFee = '0'; destinationFee = '0'; diff --git a/packages/extension-base/src/services/balance-service/transfer/xcm/utils.ts b/packages/extension-base/src/services/balance-service/transfer/xcm/utils.ts index 13ac422d80b..37e2f71921a 100644 --- a/packages/extension-base/src/services/balance-service/transfer/xcm/utils.ts +++ b/packages/extension-base/src/services/balance-service/transfer/xcm/utils.ts @@ -4,6 +4,7 @@ import { _ChainAsset, _ChainInfo } from '@subwallet/chain-list/types'; import { fetchParaSpellChainMap } from '@subwallet/extension-base/constants/paraspell-chain-map'; import { CreateXcmExtrinsicProps } from '@subwallet/extension-base/services/balance-service/transfer/xcm/index'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { ProxyServiceRoute } from '@subwallet/extension-base/types/environment'; import { fetchFromProxyService } from '@subwallet/extension-base/utils'; import BigNumber from 'bignumber.js'; @@ -13,6 +14,8 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'; import { Call, ExtrinsicPayload } from '@polkadot/types/interfaces'; import { assert, compactToU8a, isHex, u8aConcat, u8aEq } from '@polkadot/util'; +const xcmUtilsLogger = createLogger('XcmUtils'); + export type DryRunNodeFailure = { success: false, failureReason: string @@ -119,7 +122,7 @@ function txHexToSubmittableExtrinsic (api: ApiPromise, hex: string): Submittable extrinsicCall = api.createType('Call', extrinsicPayload.method.toHex()); } else { - console.error('Unable to decode data as Call, length mismatch in supplied data'); + xcmUtilsLogger.error('Unable to decode data as Call, length mismatch in supplied data'); } } catch { // final attempt, we try this as-is as a (prefixed) payload @@ -140,7 +143,7 @@ function txHexToSubmittableExtrinsic (api: ApiPromise, hex: string): Submittable return decoded; } catch (e) { - console.error('Failed to decode extrinsic hex', e); + xcmUtilsLogger.error('Failed to decode extrinsic hex', e); throw new Error('Failed to decode extrinsic hex'); } @@ -299,7 +302,7 @@ export async function estimateXcmFee (request: GetXcmFeeRequest) { const requestValue = BigNumber(value).gt(0) ? value : '1'; // avoid bug in-case estimate fee sendingValue <= 0; if (!paraSpellIdentifyV4) { - console.error('Lack of paraspell metadata'); + xcmUtilsLogger.error('Lack of paraspell metadata'); return undefined; } @@ -329,7 +332,7 @@ export async function estimateXcmFee (request: GetXcmFeeRequest) { ); if (!response.ok) { - console.error('Failed to request estimate fee'); + xcmUtilsLogger.error('Failed to request estimate fee'); return undefined; } diff --git a/packages/extension-base/src/services/buy-service/index.ts b/packages/extension-base/src/services/buy-service/index.ts index a1a91b99085..4773380b732 100644 --- a/packages/extension-base/src/services/buy-service/index.ts +++ b/packages/extension-base/src/services/buy-service/index.ts @@ -4,11 +4,14 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { ListBuyServicesResponse, ListBuyTokenResponse } from '@subwallet/extension-base/services/buy-service/types'; import { AccountChainType, BuyServiceInfo, BuyTokenInfo, OnrampAccountSupportType, SupportService } from '@subwallet/extension-base/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { fetchStaticData } from '@subwallet/extension-base/utils/fetchStaticData'; import { BehaviorSubject } from 'rxjs'; import { DEFAULT_SERVICE_INFO } from './constants'; +const buyServiceLogger = createLogger('BuyService'); + const convertSupportType = (support: OnrampAccountSupportType): AccountChainType | null => { switch (support) { case 'ETHEREUM': @@ -40,13 +43,13 @@ export default class BuyService { this.fetchTokens() .catch((e) => { - console.error('Error on fetch buy tokens', e); + buyServiceLogger.error('Error on fetch buy tokens', e); this.#state.eventService.emit('buy.tokens.ready', true); }); this.fetchServices() .catch((e) => { - console.error('Error on fetch buy services', e); + buyServiceLogger.error('Error on fetch buy services', e); this.#state.eventService.emit('buy.services.ready', true); }); } diff --git a/packages/extension-base/src/services/campaign-service/helpers.ts b/packages/extension-base/src/services/campaign-service/helpers.ts index f9775561643..eeb7044a111 100644 --- a/packages/extension-base/src/services/campaign-service/helpers.ts +++ b/packages/extension-base/src/services/campaign-service/helpers.ts @@ -3,8 +3,11 @@ import { CampaignAction, CampaignNotification, NotificationType } from '@subwallet/extension-base/background/KoniTypes'; import NotificationService from '@subwallet/extension-base/services/notification-service/NotificationService'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { t } from 'i18next'; +const campaignHelpersLogger = createLogger('CampaignHelpers'); + export const runCampaign = (notificationService: NotificationService, campaign: CampaignNotification) => { const { action, message, metadata, title } = campaign.data; const { buttons } = campaign; @@ -17,7 +20,7 @@ export const runCampaign = (notificationService: NotificationService, campaign: const url = metadata.url as string | undefined; if (url) { - chrome.tabs.create({ url }).catch(console.error); + chrome.tabs.create({ url }).catch((error) => campaignHelpersLogger.error('Error opening URL', error)); } } diff --git a/packages/extension-base/src/services/campaign-service/index.ts b/packages/extension-base/src/services/campaign-service/index.ts index 992d8947032..fd228c1b250 100644 --- a/packages/extension-base/src/services/campaign-service/index.ts +++ b/packages/extension-base/src/services/campaign-service/index.ts @@ -4,12 +4,15 @@ import { CampaignData, CampaignDataType, ShowCampaignPopupRequest } from '@subwallet/extension-base/background/KoniTypes'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { ListCampaignResponse } from '@subwallet/extension-base/services/campaign-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { TARGET_ENV } from '@subwallet/extension-base/utils'; import { fetchStaticData } from '@subwallet/extension-base/utils/fetchStaticData'; import { BehaviorSubject } from 'rxjs'; import { runCampaign } from './helpers'; +const campaignServiceLogger = createLogger('CampaignService'); + const targetEnvs = ['extension', 'mobile']; export default class CampaignService { @@ -23,12 +26,12 @@ export default class CampaignService { if (targetEnvs.includes(TARGET_ENV)) { this.fetchCampaign() .catch((e) => { - console.error('Error on fetch campaigns', e); + campaignServiceLogger.error('Error on fetch campaigns', e); }); this.runCampaign() .catch((e) => { - console.error('Error on run campaigns', e); + campaignServiceLogger.error('Error on run campaigns', e); }); } } @@ -146,7 +149,7 @@ export default class CampaignService { const onComplete = () => { this.completeCampaignNotification(slug) .catch((e) => { - console.error('Error when complete campaign', slug, e); + campaignServiceLogger.error('Error when complete campaign', slug, e); }); }; @@ -162,7 +165,7 @@ export default class CampaignService { throw new Error('Missing handle campaign'); } } catch (e) { - console.error('Error on running campaigns', slug, e); + campaignServiceLogger.error('Error on running campaigns', slug, e); } }); } diff --git a/packages/extension-base/src/services/chain-online-service/index.ts b/packages/extension-base/src/services/chain-online-service/index.ts index b47467231be..3247a41b98a 100644 --- a/packages/extension-base/src/services/chain-online-service/index.ts +++ b/packages/extension-base/src/services/chain-online-service/index.ts @@ -4,6 +4,7 @@ import { AssetLogoMap, ChainLogoMap } from '@subwallet/chain-list'; import { _AssetType, _ChainAsset, _ChainInfo, _ChainStatus } from '@subwallet/chain-list/types'; import { AssetSetting } from '@subwallet/extension-base/background/KoniTypes'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { LATEST_CHAIN_PATCH_FETCHING_INTERVAL, md5HashChainAsset, md5HashChainInfo } from '@subwallet/extension-base/services/chain-online-service/constants'; import { ChainService, filterAssetInfoMap } from '@subwallet/extension-base/services/chain-service'; import { _ChainApiStatus, _ChainConnectionStatus, _ChainState } from '@subwallet/extension-base/services/chain-service/types'; @@ -13,6 +14,8 @@ import SettingService from '@subwallet/extension-base/services/setting-service/S import { IChain } from '@subwallet/extension-base/services/storage-service/databases'; import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService'; +const chainOnlineServiceLogger = createLogger('ChainOnlineService'); + export class ChainOnlineService { private chainService: ChainService; private settingService: SettingService; @@ -359,7 +362,7 @@ export class ChainOnlineService { } } } catch (e) { - console.error('Error fetching latest patch data'); + chainOnlineServiceLogger.error('Error fetching latest patch data'); } } @@ -379,12 +382,12 @@ export class ChainOnlineService { .then(() => this.chainService.setLockChainInfoMap(false)) .catch((e) => { this.chainService.setLockChainInfoMap(false); - console.error('Error update latest patch', e); + chainOnlineServiceLogger.error('Error update latest patch', e); }) .finally(resolve); }) .catch((e) => { - console.error('Asset fail to ready', e); + chainOnlineServiceLogger.error('Asset fail to ready', e); resolve(); }); } else { @@ -392,7 +395,7 @@ export class ChainOnlineService { } }); }).catch((e) => { - console.error('Error get latest patch or data map is locking', e); + chainOnlineServiceLogger.error('Error get latest patch or data map is locking', e); }).finally(() => { this.eventService.emit('asset.online.ready', true); }); diff --git a/packages/extension-base/src/services/chain-service/handler/CardanoApi.ts b/packages/extension-base/src/services/chain-service/handler/CardanoApi.ts index b56d99e7b54..4188881c461 100644 --- a/packages/extension-base/src/services/chain-service/handler/CardanoApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/CardanoApi.ts @@ -7,10 +7,13 @@ import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/ha import { _CardanoApi, _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types'; import { ProxyServiceRoute } from '@subwallet/extension-base/types/environment'; import { createPromiseHandler, fetchFromProxyService, PromiseHandler } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BehaviorSubject } from 'rxjs'; import { hexAddPrefix, isHex } from '@polkadot/util'; +const cardanoApiLogger = createLogger('CardanoApi'); + // export const API_KEY = { // mainnet: process.env.BLOCKFROST_API_KEY_MAIN || '', // testnet: process.env.BLOCKFROST_API_KEY_PREP || '' @@ -116,7 +119,7 @@ export class CardanoApi implements _CardanoApi { onConnect (): void { if (!this.isApiConnected) { - console.log(`Connected to ${this.chainSlug} at ${this.apiUrl}`); + cardanoApiLogger.info(`Connected to ${this.chainSlug} at ${this.apiUrl}`); this.isApiReady = true; if (this.isApiReadyOnce) { @@ -131,7 +134,7 @@ export class CardanoApi implements _CardanoApi { this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); if (this.isApiConnected) { - console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl}`); + cardanoApiLogger.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl}`); this.isApiReady = false; this.isReadyHandler = createPromiseHandler<_CardanoApi>(); } @@ -149,7 +152,7 @@ export class CardanoApi implements _CardanoApi { return addressBalance.amount; } catch (e) { - console.error('Error on getting account balance', e); + cardanoApiLogger.error('Error on getting account balance', e); return []; } @@ -169,7 +172,7 @@ export class CardanoApi implements _CardanoApi { return utxos; } catch (e) { - console.error('Error on getting account balance', e); + cardanoApiLogger.error('Error on getting account balance', e); return []; } @@ -187,7 +190,7 @@ export class CardanoApi implements _CardanoApi { return utxo; } catch (e) { - console.error('Error on getting account balance', e); + cardanoApiLogger.error('Error on getting account balance', e); return {} as TransactionUtxosItem; } @@ -206,12 +209,12 @@ export class CardanoApi implements _CardanoApi { if (isHex(hexAddPrefix(hash))) { return hash; } else { - console.error('Error on submitting cardano tx'); + cardanoApiLogger.error('Error on submitting cardano tx'); return ''; } } catch (e) { - console.error('Error on submitting cardano tx', e); + cardanoApiLogger.error('Error on submitting cardano tx', e); return ''; } diff --git a/packages/extension-base/src/services/chain-service/handler/CardanoChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/CardanoChainHandler.ts index 4544e9b9c7e..541257c7385 100644 --- a/packages/extension-base/src/services/chain-service/handler/CardanoChainHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/CardanoChainHandler.ts @@ -5,6 +5,9 @@ import { ChainService } from '@subwallet/extension-base/services/chain-service'; import { AbstractChainHandler } from '@subwallet/extension-base/services/chain-service/handler/AbstractChainHandler'; import { CardanoApi } from '@subwallet/extension-base/services/chain-service/handler/CardanoApi'; import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const cardanoChainHandlerLogger = createLogger('CardanoChainHandler'); export class CardanoChainHandler extends AbstractChainHandler { private cardanoApiMap: Record = {}; @@ -37,7 +40,7 @@ export class CardanoChainHandler extends AbstractChainHandler { existed.connect(); if (apiUrl !== existed.apiUrl) { - existed.updateApiUrl(apiUrl).catch(console.error); + existed.updateApiUrl(apiUrl).catch((error) => cardanoChainHandlerLogger.error('Error updating Cardano API URL', error)); } return existed; @@ -55,7 +58,7 @@ export class CardanoChainHandler extends AbstractChainHandler { const existed = this.getCardanoApiByChain(chain); if (existed && !existed.isApiReadyOnce) { - console.log(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); + cardanoChainHandlerLogger.info(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); return existed.recoverConnect(); } @@ -64,7 +67,7 @@ export class CardanoChainHandler extends AbstractChainHandler { destroyCardanoApi (chain: string) { const cardanoApi = this.getCardanoApiByChain(chain); - cardanoApi?.destroy().catch(console.error); + cardanoApi?.destroy().catch((error) => cardanoChainHandlerLogger.error('Error destroying Cardano API', error)); } async sleep () { @@ -72,7 +75,7 @@ export class CardanoChainHandler extends AbstractChainHandler { this.cancelAllRecover(); await Promise.all(Object.values(this.getCardanoApiMap()).map((cardanoApi) => { - return cardanoApi.disconnect().catch(console.error); + return cardanoApi.disconnect().catch((error) => cardanoChainHandlerLogger.error('Error disconnecting Cardano API', error)); })); return Promise.resolve(); diff --git a/packages/extension-base/src/services/chain-service/handler/EvmApi.ts b/packages/extension-base/src/services/chain-service/handler/EvmApi.ts index 78526c6d9b0..c0cc1f8ea62 100644 --- a/packages/extension-base/src/services/chain-service/handler/EvmApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/EvmApi.ts @@ -7,10 +7,13 @@ import { EVM_PASS_CONNECT_STATUS } from '@subwallet/extension-base/services/chai import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types'; import { _ChainConnectionStatus, _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils/promise'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BehaviorSubject } from 'rxjs'; import Web3 from 'web3'; import { HttpProvider, WebsocketProvider } from 'web3-core'; +const evmApiLogger = createLogger('EvmApi'); + export class EvmApi implements _EvmApi { chainSlug: string; api: Web3; @@ -132,7 +135,7 @@ export class EvmApi implements _EvmApi { this.isApiReady = false; this.isReadyHandler.reject(error); this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); - console.warn(`Can not connect to ${this.chainSlug} (EVM) at ${this.apiUrl}`); + evmApiLogger.warn(`Can not connect to ${this.chainSlug} (EVM) at ${this.apiUrl}`); }); // Interval to check connecting status @@ -162,7 +165,7 @@ export class EvmApi implements _EvmApi { this.isReadyHandler.resolve(this); if (!this.isApiConnected) { - console.log(`Connected to ${this.chainSlug} at ${this.apiUrl}`); + evmApiLogger.info(`Connected to ${this.chainSlug} at ${this.apiUrl}`); this.isApiReady = true; } @@ -173,7 +176,7 @@ export class EvmApi implements _EvmApi { this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); if (this.isApiConnected) { - console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl} (EVM)`); + evmApiLogger.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl} (EVM)`); this.isApiReady = false; this.isReadyHandler = createPromiseHandler<_EvmApi>(); } diff --git a/packages/extension-base/src/services/chain-service/handler/EvmChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/EvmChainHandler.ts index bd138a657d9..15035f1642b 100644 --- a/packages/extension-base/src/services/chain-service/handler/EvmChainHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/EvmChainHandler.ts @@ -13,6 +13,9 @@ import { Contract } from 'web3-eth-contract'; import { logger as createLogger } from '@polkadot/util/logger'; import { Logger } from '@polkadot/util/types'; +import { createLogger as createSubWalletLogger } from '@subwallet/extension-base/utils/logger'; + +const evmChainHandlerLogger = createSubWalletLogger('EvmChainHandler'); export class EvmChainHandler extends AbstractChainHandler { private evmApiMap: Record = {}; @@ -46,7 +49,7 @@ export class EvmChainHandler extends AbstractChainHandler { existed.connect(); if (apiUrl !== existed.apiUrl) { - existed.updateApiUrl(apiUrl).catch(console.error); + existed.updateApiUrl(apiUrl).catch((error) => evmChainHandlerLogger.error('Error updating EVM API URL', error)); } return existed; @@ -64,7 +67,7 @@ export class EvmChainHandler extends AbstractChainHandler { const existed = this.getEvmApiByChain(chainSlug); if (existed && !existed.isApiReadyOnce) { - console.log(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); + evmChainHandlerLogger.info(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); return existed.recoverConnect(); } @@ -73,7 +76,7 @@ export class EvmChainHandler extends AbstractChainHandler { destroyEvmApi (chain: string) { const evmApi = this.getEvmApiByChain(chain); - evmApi?.destroy().catch(console.error); + evmApi?.destroy().catch((error) => evmChainHandlerLogger.error('Error destroying EVM API', error)); } async sleep () { @@ -81,7 +84,7 @@ export class EvmChainHandler extends AbstractChainHandler { this.cancelAllRecover(); await Promise.all(Object.values(this.getEvmApiMap()).map((evmApi) => { - return evmApi.disconnect().catch(console.error); + return evmApi.disconnect().catch((error) => evmChainHandlerLogger.error('Error disconnecting EVM API', error)); })); return Promise.resolve(); diff --git a/packages/extension-base/src/services/chain-service/handler/SubstrateApi.ts b/packages/extension-base/src/services/chain-service/handler/SubstrateApi.ts index fb56fead7fa..b47c7fe628e 100644 --- a/packages/extension-base/src/services/chain-service/handler/SubstrateApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/SubstrateApi.ts @@ -14,8 +14,11 @@ import { _ChainConnectionStatus, _SubstrateAdapterQueryArgs, _SubstrateAdapterSu import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils/promise'; import { goldbergRpc, goldbergTypes, spec as availSpec } from 'avail-js-sdk'; import { BehaviorSubject, combineLatest, map, Observable, Subscription } from 'rxjs'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { ApiPromise, WsProvider } from '@polkadot/api'; + +const substrateApiLogger = createLogger('SubstrateApi'); import { ApiOptions } from '@polkadot/api/types'; import { typesBundle as _typesBundle } from '@polkadot/apps-config/api'; import { ProviderInterface } from '@polkadot/rpc-provider/types'; @@ -207,8 +210,8 @@ export class SubstrateApi implements _SubstrateApi { this.api.isReady.then(() => { this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED); _callbackUpdateMetadata?.(this); - }).catch(console.error); - }).catch(console.error); + }).catch((error) => substrateApiLogger.error('Error in SubstrateApi subscription', error)); + }).catch((error) => substrateApiLogger.error('Error in SubstrateApi operation', error)); } } @@ -216,7 +219,7 @@ export class SubstrateApi implements _SubstrateApi { try { await this.api.disconnect(); } catch (e) { - console.error(e); + substrateApiLogger.error('Error in SubstrateApi', e); } this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); @@ -247,7 +250,7 @@ export class SubstrateApi implements _SubstrateApi { onConnect (): void { this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED); this.substrateRetry = 0; - console.log(`Connected to ${this.chainSlug || ''} at ${this.apiUrl}`); + substrateApiLogger.info(`Connected to ${this.chainSlug || ''} at ${this.apiUrl}`); if (this.isApiReadyOnce) { this.handleApiReady.resolve(this); @@ -257,7 +260,7 @@ export class SubstrateApi implements _SubstrateApi { onDisconnect (): void { this.isApiReady = false; - console.log(`Disconnected from ${this.chainSlug} at ${this.apiUrl}`); + substrateApiLogger.info(`Disconnected from ${this.chainSlug} at ${this.apiUrl}`); this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); this.handleApiReady = createPromiseHandler<_SubstrateApi>(); this.substrateRetry += 1; @@ -265,12 +268,12 @@ export class SubstrateApi implements _SubstrateApi { if (this.substrateRetry > 9) { this.disconnect().then(() => { this.updateConnectionStatus(_ChainConnectionStatus.UNSTABLE); - }).catch(console.error); + }).catch((error) => substrateApiLogger.error('Error disconnecting SubstrateApi', error)); } } onError (e: Error): void { - console.warn(`${this.chainSlug} connection got error`, e); + substrateApiLogger.warn(`${this.chainSlug} connection got error`, e); } async fillApiInfo (): Promise { diff --git a/packages/extension-base/src/services/chain-service/handler/SubstrateChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/SubstrateChainHandler.ts index 9efe82202d6..59590f50149 100644 --- a/packages/extension-base/src/services/chain-service/handler/SubstrateChainHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/SubstrateChainHandler.ts @@ -17,6 +17,9 @@ import { Registry } from '@polkadot/types/types'; import { BN } from '@polkadot/util'; import { logger as createLogger } from '@polkadot/util/logger'; import { Logger } from '@polkadot/util/types'; +import { createLogger as createSubWalletLogger } from '@subwallet/extension-base/utils/logger'; + +const substrateChainHandlerLogger = createSubWalletLogger('SubstrateChainHandler'); import { _PSP22_ABI, _PSP34_ABI } from '../../../koni/api/contract-handler/utils'; @@ -78,7 +81,7 @@ export class SubstrateChainHandler extends AbstractChainHandler { this.cancelAllRecover(); await Promise.all(Object.values(this.getSubstrateApiMap()).map((substrateApi) => { - return substrateApi.disconnect().catch(console.error); + return substrateApi.disconnect().catch((error) => substrateChainHandlerLogger.error('Error disconnecting Substrate API', error)); })); } @@ -86,7 +89,7 @@ export class SubstrateChainHandler extends AbstractChainHandler { const existed = this.getSubstrateApiByChain(chainSlug); if (existed && !existed.isApiReadyOnce) { - console.log(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); + substrateChainHandlerLogger.info(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); return existed.recoverConnect(); } @@ -189,9 +192,9 @@ export class SubstrateChainHandler extends AbstractChainHandler { if (!(apiPromise instanceof GearApi)) { if (tokenType === _AssetType.GRC20) { - console.warn('Cannot subscribe GRC20 balance without GearApi instance'); + substrateChainHandlerLogger.warn('Cannot subscribe GRC20 balance without GearApi instance'); } else if (tokenType === _AssetType.VFT) { - console.warn('Cannot subscribe VFT balance without GearApi instance'); + substrateChainHandlerLogger.warn('Cannot subscribe VFT balance without GearApi instance'); } tokenSmartContract.contractError = true; @@ -302,7 +305,7 @@ export class SubstrateChainHandler extends AbstractChainHandler { public destroySubstrateApi (chainSlug: string) { const substrateAPI = this.substrateApiMap[chainSlug]; - substrateAPI?.destroy().catch(console.error); + substrateAPI?.destroy().catch((error) => substrateChainHandlerLogger.error('Error destroying Substrate API', error)); } public async initApi (chainSlug: string, apiUrl: string, { externalApiPromise, onUpdateStatus, providerName }: Omit<_ApiOptions, 'metadata'> = {}): Promise<_SubstrateApi> { diff --git a/packages/extension-base/src/services/chain-service/handler/TonApi.ts b/packages/extension-base/src/services/chain-service/handler/TonApi.ts index 009a75a0ade..1e50f00d4f9 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonApi.ts @@ -11,8 +11,11 @@ import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/ import { TonWalletContract } from '@subwallet/keyring/types'; import { Cell } from '@ton/core'; import { Address, Contract, OpenedContract, TonClient } from '@ton/ton'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BehaviorSubject } from 'rxjs'; +const tonApiLogger = createLogger('TonApi'); + export class TonApi implements _TonApi { chainSlug: string; private api: TonClient; @@ -112,7 +115,7 @@ export class TonApi implements _TonApi { onConnect (): void { if (!this.isApiConnected) { - console.log(`Connected to ${this.chainSlug} at ${this.apiUrl}`); + tonApiLogger.info(`Connected to ${this.chainSlug} at ${this.apiUrl}`); this.isApiReady = true; if (this.isApiReadyOnce) { @@ -127,7 +130,7 @@ export class TonApi implements _TonApi { this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); if (this.isApiConnected) { - console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl}`); + tonApiLogger.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl}`); this.isApiReady = false; this.isReadyHandler = createPromiseHandler<_TonApi>(); } @@ -179,7 +182,7 @@ export class TonApi implements _TonApi { return extMsgInfo.result.hash; } catch (error) { - console.error('Failed to send transaction with boc', boc); + tonApiLogger.error('Failed to send transaction with boc', boc); throw error; } } diff --git a/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts index b5aebbf2e75..ae8a180fe63 100644 --- a/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/TonChainHandler.ts @@ -5,6 +5,9 @@ import { ChainService } from '@subwallet/extension-base/services/chain-service'; import { AbstractChainHandler } from '@subwallet/extension-base/services/chain-service/handler/AbstractChainHandler'; import { TonApi } from '@subwallet/extension-base/services/chain-service/handler/TonApi'; import { _ApiOptions } from '@subwallet/extension-base/services/chain-service/handler/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const tonChainHandlerLogger = createLogger('TonChainHandler'); export class TonChainHandler extends AbstractChainHandler { private tonApiMap: Record = {}; @@ -37,7 +40,7 @@ export class TonChainHandler extends AbstractChainHandler { existed.connect(); if (apiUrl !== existed.apiUrl) { - existed.updateApiUrl(apiUrl).catch(console.error); + existed.updateApiUrl(apiUrl).catch((error) => tonChainHandlerLogger.error('Error updating TON API URL', error)); } return existed; @@ -55,7 +58,7 @@ export class TonChainHandler extends AbstractChainHandler { const existed = this.getTonApiByChain(chain); if (existed && !existed.isApiReadyOnce) { - console.log(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); + tonChainHandlerLogger.info(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); return existed.recoverConnect(); } @@ -64,7 +67,7 @@ export class TonChainHandler extends AbstractChainHandler { destroyTonApi (chain: string) { const tonApi = this.getTonApiByChain(chain); - tonApi?.destroy().catch(console.error); + tonApi?.destroy().catch((error) => tonChainHandlerLogger.error('Error destroying TON API', error)); } async sleep () { @@ -72,7 +75,7 @@ export class TonChainHandler extends AbstractChainHandler { this.cancelAllRecover(); await Promise.all(Object.values(this.getTonApiMap()).map((tonApi) => { - return tonApi.disconnect().catch(console.error); + return tonApi.disconnect().catch((error) => tonChainHandlerLogger.error('Error disconnecting TON API', error)); })); return Promise.resolve(); diff --git a/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinApi.ts b/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinApi.ts index 40a27967dfb..26504d0bb80 100644 --- a/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinApi.ts +++ b/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinApi.ts @@ -5,11 +5,14 @@ import { BlockStreamTestnetRequestStrategy, MempoolTestnetRequestStrategy } from import { SubWalletMainnetRequestStrategy } from '@subwallet/extension-base/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet'; import { BitcoinApiStrategy } from '@subwallet/extension-base/services/chain-service/handler/bitcoin/strategy/types'; import { createPromiseHandler, PromiseHandler } from '@subwallet/extension-base/utils/promise'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BehaviorSubject } from 'rxjs'; import { _ApiOptions } from '../../handler/types'; import { _BitcoinApi, _ChainConnectionStatus } from '../../types'; +const bitcoinApiLogger = createLogger('BitcoinApi'); + // const isBlockStreamProvider = (apiUrl: string): boolean => apiUrl === 'https://blockstream-testnet.openbit.app' || apiUrl === 'https://electrs.openbit.app'; // const BLOCKSTREAM_TESTNET_API_URL = 'https://blockstream.info/testnet/api/'; // const MEMPOOL_TESTNET_V4_API_URL = 'https://mempool.space/testnet4/api/'; @@ -113,7 +116,7 @@ export class BitcoinApi implements _BitcoinApi { onConnect (): void { if (!this.isApiConnected) { - console.log(`Connected to ${this.chainSlug} at ${this.apiUrl}`); + bitcoinApiLogger.info(`Connected to ${this.chainSlug} at ${this.apiUrl}`); this.isApiReady = true; if (this.isApiReadyOnce) { @@ -128,7 +131,7 @@ export class BitcoinApi implements _BitcoinApi { this.updateConnectionStatus(_ChainConnectionStatus.DISCONNECTED); if (this.isApiConnected) { - console.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl}`); + bitcoinApiLogger.warn(`Disconnected from ${this.chainSlug} of ${this.apiUrl}`); this.isApiReady = false; this.isReadyHandler = createPromiseHandler<_BitcoinApi>(); } diff --git a/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinChainHandler.ts b/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinChainHandler.ts index 85da1abadfd..e948bfe00c2 100644 --- a/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinChainHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/bitcoin/BitcoinChainHandler.ts @@ -2,8 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { ChainService } from '@subwallet/extension-base/services/chain-service'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { AbstractChainHandler } from '../AbstractChainHandler'; + +const bitcoinChainHandlerLogger = createLogger('BitcoinChainHandler'); import { _ApiOptions } from '../types'; import { BitcoinApi } from './BitcoinApi'; @@ -34,7 +37,7 @@ export class BitcoinChainHandler extends AbstractChainHandler { existed.connect(); if (apiUrl !== existed.apiUrl) { - existed.updateApiUrl(apiUrl).catch(console.error); + existed.updateApiUrl(apiUrl).catch((error) => bitcoinChainHandlerLogger.error('Error updating Bitcoin API URL', error)); } return existed; @@ -52,7 +55,7 @@ export class BitcoinChainHandler extends AbstractChainHandler { const existed = this.getApiByChain(chainSlug); if (existed && !existed.isApiReadyOnce) { - console.log(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); + bitcoinChainHandlerLogger.info(`Reconnect ${existed.providerName || existed.chainSlug} at ${existed.apiUrl}`); return existed.recoverConnect(); } @@ -61,7 +64,7 @@ export class BitcoinChainHandler extends AbstractChainHandler { destroyApi (chain: string) { const api = this.getApiByChain(chain); - api?.destroy().catch(console.error); + api?.destroy().catch((error) => bitcoinChainHandlerLogger.error('Error destroying Bitcoin API', error)); } async sleep () { @@ -69,7 +72,7 @@ export class BitcoinChainHandler extends AbstractChainHandler { this.cancelAllRecover(); await Promise.all(Object.values(this.getApiMap()).map((evmApi) => { - return evmApi.disconnect().catch(console.error); + return evmApi.disconnect().catch((error) => bitcoinChainHandlerLogger.error('Error disconnecting Bitcoin API', error)); })); return Promise.resolve(); diff --git a/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/blockstream-testnet-strategy.ts b/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/blockstream-testnet-strategy.ts index 4e32b55d560..6f244718d6f 100644 --- a/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/blockstream-testnet-strategy.ts +++ b/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/blockstream-testnet-strategy.ts @@ -3,6 +3,7 @@ import { SWError } from '@subwallet/extension-base/background/errors/SWError'; import { BitcoinAddressSummaryInfo, BitcoinApiStrategy, BitcoinTransactionEventMap, BlockstreamAddressResponse, BlockStreamBlock, BlockStreamFeeEstimates, BlockStreamTransactionDetail, BlockStreamTransactionStatus, BlockStreamUtxo, Inscription, InscriptionFetchedData, RunesInfoByAddress, RunesInfoByAddressFetchedData } from '@subwallet/extension-base/services/chain-service/handler/bitcoin/strategy/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { HiroService } from '@subwallet/extension-base/services/hiro-service'; import { RunesService } from '@subwallet/extension-base/services/rune-service'; import { BaseApiRequestStrategy } from '@subwallet/extension-base/strategy/api-request-strategy'; @@ -12,6 +13,8 @@ import { BitcoinFeeInfo, BitcoinTx, UtxoResponseItem } from '@subwallet/extensio import BigN from 'bignumber.js'; import EventEmitter from 'eventemitter3'; +const blockstreamTestnetLogger = createLogger('BlockStreamTestnetStrategy'); + export class BlockStreamTestnetRequestStrategy extends BaseApiRequestStrategy implements BitcoinApiStrategy { private readonly baseUrl: string; private readonly isTestnet: boolean; @@ -67,7 +70,7 @@ export class BlockStreamTestnetRequestStrategy extends BaseApiRequestStrategy im this.timePerBlock = blockTime; } catch (e) { - console.error('Failed to compute block time', e); + blockstreamTestnetLogger.error('Failed to compute block time', e); blockTime = (this.isTestnet ? 5 * 60 : 10 * 60) * 1000; // Default to 10 minutes if failed } @@ -220,7 +223,7 @@ export class BlockStreamTestnetRequestStrategy extends BaseApiRequestStrategy im const response = await getRequest(this.getUrl('/fee-estimates'), undefined, this.headers); if (!response.ok) { - console.warn(`Failed to fetch fee estimates: ${response.statusText}`); + blockstreamTestnetLogger.warn(`Failed to fetch fee estimates: ${response.statusText}`); return defaultFeeInfo; } @@ -300,7 +303,7 @@ export class BlockStreamTestnetRequestStrategy extends BaseApiRequestStrategy im eventEmitter.emit('success', transactionStatus); } }) - .catch(console.error); + .catch((error) => blockstreamTestnetLogger.error('Error in blockstream testnet strategy', error)); }, 30000); }) .catch((error: Error) => { @@ -351,7 +354,7 @@ export class BlockStreamTestnetRequestStrategy extends BaseApiRequestStrategy im return runesFullList; } catch (error) { - console.error(`Failed to get ${address} balances`, error); + blockstreamTestnetLogger.error(`Failed to get ${address} balances`, error); throw error; } } diff --git a/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/mempool-testnet-strategy.ts b/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/mempool-testnet-strategy.ts index 7182a9f2eb7..f92d26f15a3 100644 --- a/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/mempool-testnet-strategy.ts +++ b/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/BlockStreamTestnet/mempool-testnet-strategy.ts @@ -3,6 +3,7 @@ import { SWError } from '@subwallet/extension-base/background/errors/SWError'; import { BitcoinAddressSummaryInfo, BitcoinApiStrategy, BitcoinTransactionEventMap, BlockstreamAddressResponse, BlockStreamBlock, BlockStreamFeeEstimates, BlockStreamTransactionDetail, BlockStreamTransactionStatus, BlockStreamUtxo, Inscription, InscriptionFetchedData, RecommendedFeeEstimates, RunesInfoByAddress, RunesInfoByAddressFetchedData } from '@subwallet/extension-base/services/chain-service/handler/bitcoin/strategy/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { HiroService } from '@subwallet/extension-base/services/hiro-service'; import { RunesService } from '@subwallet/extension-base/services/rune-service'; import { BaseApiRequestStrategy } from '@subwallet/extension-base/strategy/api-request-strategy'; @@ -12,6 +13,8 @@ import { BitcoinFeeInfo, BitcoinTx, UtxoResponseItem } from '@subwallet/extensio import BigN from 'bignumber.js'; import EventEmitter from 'eventemitter3'; +const mempoolTestnetLogger = createLogger('MempoolTestnetStrategy'); + export class MempoolTestnetRequestStrategy extends BaseApiRequestStrategy implements BitcoinApiStrategy { private readonly baseUrl: string; private readonly isTestnet: boolean; @@ -67,7 +70,7 @@ export class MempoolTestnetRequestStrategy extends BaseApiRequestStrategy implem this.timePerBlock = blockTime; } catch (e) { - console.error('Failed to compute block time', e); + mempoolTestnetLogger.error('Failed to compute block time', e); blockTime = (this.isTestnet ? 5 * 60 : 10 * 60) * 1000; // Default to 10 minutes if failed } @@ -220,7 +223,7 @@ export class MempoolTestnetRequestStrategy extends BaseApiRequestStrategy implem const response = await getRequest(this.getUrl('v1/fees/recommended'), undefined, this.headers); if (!response.ok) { - console.warn(`Failed to fetch fee estimates: ${response.statusText}`); + mempoolTestnetLogger.warn(`Failed to fetch fee estimates: ${response.statusText}`); return defaultFeeInfo; } @@ -300,7 +303,7 @@ export class MempoolTestnetRequestStrategy extends BaseApiRequestStrategy implem eventEmitter.emit('success', transactionStatus); } }) - .catch(console.error); + .catch((error) => mempoolTestnetLogger.error('Error in mempool testnet strategy', error)); }, 30000); }) .catch((error: Error) => { @@ -351,7 +354,7 @@ export class MempoolTestnetRequestStrategy extends BaseApiRequestStrategy implem return runesFullList; } catch (error) { - console.error(`Failed to get ${address} balances`, error); + mempoolTestnetLogger.error(`Failed to get ${address} balances`, error); throw error; } } diff --git a/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet/index.ts b/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet/index.ts index 2e3805107ee..f33d5d8224d 100644 --- a/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet/index.ts +++ b/packages/extension-base/src/services/chain-service/handler/bitcoin/strategy/SubWalletMainnet/index.ts @@ -5,6 +5,7 @@ import { SWError } from '@subwallet/extension-base/background/errors/SWError'; import { _BTC_SERVICE_TOKEN } from '@subwallet/extension-base/services/chain-service/constants'; import { BitcoinAddressSummaryInfo, BitcoinApiStrategy, BitcoinTransactionEventMap, BlockStreamBlock, BlockStreamFeeEstimates, BlockStreamTransactionDetail, BlockStreamTransactionStatus, Inscription, InscriptionFetchedData, RecommendedFeeEstimates, RunesInfoByAddress, RunesInfoByAddressFetchedData, UpdateOpenBitUtxo } from '@subwallet/extension-base/services/chain-service/handler/bitcoin/strategy/types'; import { OBResponse } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { HiroService } from '@subwallet/extension-base/services/hiro-service'; import { RunesService } from '@subwallet/extension-base/services/rune-service'; import { BaseApiRequestStrategy } from '@subwallet/extension-base/strategy/api-request-strategy'; @@ -14,6 +15,8 @@ import { BitcoinFeeInfo, BitcoinTx, UtxoResponseItem } from '@subwallet/extensio import BigN from 'bignumber.js'; import EventEmitter from 'eventemitter3'; +const subWalletMainnetLogger = createLogger('SubWalletMainnetStrategy'); + export class SubWalletMainnetRequestStrategy extends BaseApiRequestStrategy implements BitcoinApiStrategy { private readonly baseUrl: string; private readonly isTestnet: boolean; @@ -71,7 +74,7 @@ export class SubWalletMainnetRequestStrategy extends BaseApiRequestStrategy impl this.timePerBlock = blockTime; } catch (e) { - console.error('Failed to compute block time', e); + subWalletMainnetLogger.error('Failed to compute block time', e); blockTime = (this.isTestnet ? 5 * 60 : 10 * 60) * 1000; // Default to 10 minutes if failed } @@ -238,7 +241,7 @@ export class SubWalletMainnetRequestStrategy extends BaseApiRequestStrategy impl eventEmitter.emit('success', transactionStatus); } }) - .catch(console.error); + .catch((error) => subWalletMainnetLogger.error('Error in SubWalletMainnet strategy', error)); }, 30000); }) .catch((error: Error) => { @@ -288,7 +291,7 @@ export class SubWalletMainnetRequestStrategy extends BaseApiRequestStrategy impl return runesFullList; } catch (error) { - console.error(`Failed to get ${address} balances`, error); + subWalletMainnetLogger.error(`Failed to get ${address} balances`, error); throw error; } } @@ -301,7 +304,7 @@ export class SubWalletMainnetRequestStrategy extends BaseApiRequestStrategy impl return responseRuneUtxos.results; } catch (error) { - console.error(`Failed to get ${address} rune utxos`, error); + subWalletMainnetLogger.error(`Failed to get ${address} rune utxos`, error); throw error; } } @@ -333,7 +336,7 @@ export class SubWalletMainnetRequestStrategy extends BaseApiRequestStrategy impl return inscriptionsFullList; } catch (error) { - console.error(`Failed to get ${address} inscriptions`, error); + subWalletMainnetLogger.error(`Failed to get ${address} inscriptions`, error); throw error; } } diff --git a/packages/extension-base/src/services/chain-service/handler/light-client/index.ts b/packages/extension-base/src/services/chain-service/handler/light-client/index.ts index a476f723752..3319097b3ab 100644 --- a/packages/extension-base/src/services/chain-service/handler/light-client/index.ts +++ b/packages/extension-base/src/services/chain-service/handler/light-client/index.ts @@ -6,6 +6,9 @@ import { WellKnownChain } from '@substrate/connect'; import { ScProvider } from '@polkadot/rpc-provider'; import { ProviderInterface, ProviderInterfaceCallback, ProviderInterfaceEmitCb, ProviderInterfaceEmitted } from '@polkadot/rpc-provider/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const lightClientLogger = createLogger('LightClient'); export const relayChainSpecs: Record = { kusama: WellKnownChain.ksmcc3, @@ -35,7 +38,7 @@ class ProviderPlaceholder implements ProviderInterface { .then((provider) => { this.provider = provider; }) - .catch(console.error); + .catch((error) => lightClientLogger.error('Error initializing provider', error)); } get hasSubscriptions () { @@ -84,7 +87,7 @@ class ProviderPlaceholder implements ProviderInterface { if (!cancel) { unsub = provider.on(type, sub); } - }).catch(console.error); + }).catch((error) => lightClientLogger.error('Error setting up provider subscription', error)); return () => { unsub(); @@ -138,7 +141,10 @@ export function getSubstrateConnectProvider (specLink: string): ProviderInterfac scProvider = new ScProvider(Sc, spec); return scProvider; - }).catch(console.error) as Promise; + }).catch((error) => { + lightClientLogger.error('Error fetching para chain spec', error); + throw error; + }) as Promise; return new ProviderPlaceholder(scPromise); } diff --git a/packages/extension-base/src/services/chain-service/handler/manta/MantaPrivateHandler.ts b/packages/extension-base/src/services/chain-service/handler/manta/MantaPrivateHandler.ts index df237b62e51..8e361680239 100644 --- a/packages/extension-base/src/services/chain-service/handler/manta/MantaPrivateHandler.ts +++ b/packages/extension-base/src/services/chain-service/handler/manta/MantaPrivateHandler.ts @@ -3,9 +3,12 @@ import { MantaAuthorizationContext, MantaPayConfig, MantaPaySyncState } from '@subwallet/extension-base/background/KoniTypes'; import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BaseWallet, interfaces, MantaPayWallet } from 'manta-extension-sdk'; import { Subject } from 'rxjs'; +const mantaPrivateHandlerLogger = createLogger('MantaPrivateHandler'); + export class MantaPrivateHandler { private dbService: DatabaseService; private _privateWallet: MantaPayWallet | undefined = undefined; @@ -85,7 +88,7 @@ export class MantaPrivateHandler { ...data }); } catch (e) { - console.error('manta-pay', e); + mantaPrivateHandlerLogger.error('manta-pay error', e); return false; } @@ -102,7 +105,7 @@ export class MantaPrivateHandler { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment result = await this.dbService.getMantaPayData(`storage_state_${palletName}_${network}${suffix}`); } catch (e) { - console.error(e); + mantaPrivateHandlerLogger.error('Error in MantaPrivateHandler', e); } // eslint-disable-next-line @typescript-eslint/no-unsafe-return @@ -167,7 +170,7 @@ export class MantaPrivateHandler { this.syncStateSubject.next(this.syncState); }) - .catch(console.error); + .catch((error) => mantaPrivateHandlerLogger.error('Error in MantaPrivateHandler operation', error)); }, 1000); return () => { diff --git a/packages/extension-base/src/services/chain-service/health-check/index.ts b/packages/extension-base/src/services/chain-service/health-check/index.ts index 0c33fe5c93f..776863bfa89 100644 --- a/packages/extension-base/src/services/chain-service/health-check/index.ts +++ b/packages/extension-base/src/services/chain-service/health-check/index.ts @@ -2,10 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import { _ChainInfo } from '@subwallet/chain-list/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import Web3 from 'web3'; import { WsProvider } from '@polkadot/api'; +const healthCheckLogger = createLogger('HealthCheck'); + export async function checkSubstrateEndpoint (endpoint: string, timeout: number): Promise { const wsProvider = new WsProvider(endpoint, false, undefined, timeout); @@ -16,11 +19,11 @@ export async function checkSubstrateEndpoint (endpoint: string, timeout: number) wsProvider.on('connected', () => { wsProvider.send('system_health', []).then((systemHealth) => { resolve(true); - }).catch(console.log); + }).catch((error) => healthCheckLogger.debug('Error checking system health', error)); }); }); } catch (error) { - console.log(`${endpoint}: fail to check health`); + healthCheckLogger.warn(`${endpoint}: fail to check health`); return false; // if there is an error, return false } finally { @@ -36,7 +39,7 @@ export async function checkEvmEndpoint (endpoint: string, timeout: number): Prom return !!blockNumber; } catch (error) { - console.log(error); + healthCheckLogger.error('Error checking EVM endpoint', error); return false; } diff --git a/packages/extension-base/src/services/chain-service/health-check/utils/asset-info.ts b/packages/extension-base/src/services/chain-service/health-check/utils/asset-info.ts index a5660b6eb1a..629c956ed84 100644 --- a/packages/extension-base/src/services/chain-service/health-check/utils/asset-info.ts +++ b/packages/extension-base/src/services/chain-service/health-check/utils/asset-info.ts @@ -7,11 +7,14 @@ import { _PSP22_ABI } from '@subwallet/extension-base/koni/api/contract-handler/ import { getDefaultWeightV2 } from '@subwallet/extension-base/koni/api/contract-handler/wasm/utils'; import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import BigN from 'bignumber.js'; import { ApiPromise } from '@polkadot/api'; import { ContractPromise } from '@polkadot/api-contract'; +const assetInfoLogger = createLogger('AssetInfo'); + const BN_TEN = new BigN(10); export interface AssetSpec { @@ -412,9 +415,9 @@ export const validateAsset = ( const chainlistDecimals = chainlistAsset.decimals || 0; const chainlistSymbol = chainlistAsset.symbol; - console.log(`[i] minAmount: current - ${chainlistMinAmount}, onchain - ${minAmount}`); - console.log(`[i] decimals: current - ${chainlistDecimals}, onchain - ${decimals}`); - console.log(`[i] symbol: current - ${chainlistSymbol}, onchain - ${symbol}`); + assetInfoLogger.info(`[i] minAmount: current - ${chainlistMinAmount}, onchain - ${minAmount}`); + assetInfoLogger.info(`[i] decimals: current - ${chainlistDecimals}, onchain - ${decimals}`); + assetInfoLogger.info(`[i] symbol: current - ${chainlistSymbol}, onchain - ${symbol}`); const isValidSymbol = symbol === chainlistSymbol ? true : 'zk' + symbol === chainlistSymbol; const isValidMinAmount = minAmount === chainlistMinAmount; diff --git a/packages/extension-base/src/services/chain-service/health-check/utils/provider.ts b/packages/extension-base/src/services/chain-service/health-check/utils/provider.ts index 6a12c55a764..5d3e5ceae49 100644 --- a/packages/extension-base/src/services/chain-service/health-check/utils/provider.ts +++ b/packages/extension-base/src/services/chain-service/health-check/utils/provider.ts @@ -3,17 +3,20 @@ import { EvmApi } from '@subwallet/extension-base/services/chain-service/handler/EvmApi'; import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { ApiPromise, WsProvider } from '@polkadot/api'; import { noop } from '@polkadot/util'; +const providerHealthCheckLogger = createLogger('ProviderHealthCheck'); + export const failedMessage = 'Connect failed'; export const timeoutMessage = 'Connect timeout'; export const substrateHandleConnectChain = async (chain: string, key: string, provider: string, hash: string): Promise<[ApiPromise, string]> => { // eslint-disable-next-line @typescript-eslint/no-misused-promises,no-async-promise-executor return new Promise<[ApiPromise, string]>(async (resolve) => { - console.log('start', chain, key, provider); + providerHealthCheckLogger.debug('start', chain, key, provider); const _api = new ApiPromise({ provider: new WsProvider(provider) }); @@ -21,7 +24,7 @@ export const substrateHandleConnectChain = async (chain: string, key: string, pr const handlerOnFail = (e: Error) => { if (logFail) { - console.log('error', chain, key); + providerHealthCheckLogger.error('error', chain, key); resolve([_api, e?.message || failedMessage]); } @@ -29,11 +32,11 @@ export const substrateHandleConnectChain = async (chain: string, key: string, pr }; const timeout = setTimeout(() => { - console.log('timeout', chain, key); + providerHealthCheckLogger.warn('timeout', chain, key); resolve([_api, timeoutMessage]); logFail = false; - _api.disconnect().catch(console.error); + _api.disconnect().catch((error) => providerHealthCheckLogger.error('Error disconnecting API', error)); _api.off('disconnected', handlerOnFail); _api.off('error', handlerOnFail); }, 30 * 1000); @@ -64,7 +67,7 @@ export const substrateHandleConnectChain = async (chain: string, key: string, pr export const evmHandleConnectChain = async (chain: string, key: string, provider: string, chainId: number): Promise<[_EvmApi | null, string]> => { // eslint-disable-next-line @typescript-eslint/no-misused-promises,no-async-promise-executor return new Promise<[_EvmApi | null, string]>(async (resolve) => { - console.log('start', chain, key, provider); + providerHealthCheckLogger.debug('start', chain, key, provider); let api: _EvmApi | null = null; @@ -74,7 +77,7 @@ export const evmHandleConnectChain = async (chain: string, key: string, provider const handlerOnFail = (e: Error) => { if (logFail) { - console.log('error', chain, key); + providerHealthCheckLogger.error('error', chain, key); resolve([api, e?.message || failedMessage]); } @@ -82,11 +85,11 @@ export const evmHandleConnectChain = async (chain: string, key: string, provider }; const timeout = setTimeout(() => { - console.log('timeout', chain, key); + providerHealthCheckLogger.warn('timeout', chain, key); resolve([api, timeoutMessage]); logFail = false; - _api.destroy().catch(console.error); + _api.destroy().catch((error) => providerHealthCheckLogger.error('Error destroying API', error)); }, 60 * 1000); try { @@ -208,7 +211,7 @@ export const handleEvmProvider = ({ awaitDisconnect, } }; - console.log('connected', chain, key, provider); + providerHealthCheckLogger.debug('connected', chain, key, provider); clearTimeout(timeout); diff --git a/packages/extension-base/src/services/chain-service/index.ts b/packages/extension-base/src/services/chain-service/index.ts index ccb035417e7..e55f8df7f23 100644 --- a/packages/extension-base/src/services/chain-service/index.ts +++ b/packages/extension-base/src/services/chain-service/index.ts @@ -30,6 +30,7 @@ import { isArray } from '@polkadot/util'; import { logger as createLogger } from '@polkadot/util/logger'; import { HexString, Logger } from '@polkadot/util/types'; import { ExtraInfo } from '@polkadot-api/merkleize-metadata'; +import { createLogger as createExtensionLogger } from '@subwallet/extension-base/utils/logger'; const filterChainInfoMap = (data: Record, ignoredChains: string[]): Record => { return Object.fromEntries( @@ -39,6 +40,8 @@ const filterChainInfoMap = (data: Record, ignoredChains: str }; // .filter(([slug, info]) => !info.bitcoinInfo && !ignoredChains.includes(slug)) +const chainServiceLogger = createExtensionLogger('ChainService'); + const ignoredList = [ 'bevm', 'bevmTest', @@ -130,7 +133,7 @@ export class ChainService { this.swapRefMapSubject.next(this.swapRefMap); if (MODULE_SUPPORT.MANTA_ZK) { - console.log('Init Manta ZK'); + chainServiceLogger.info('Init Manta ZK'); this.mantaChainHandler = new MantaPrivateHandler(dbService); } @@ -614,7 +617,7 @@ export class ChainService { delete chainStateMap[slug]; delete chainInfoMap[slug]; this.deleteAssetsByChain(slug); - this.dbService.removeFromChainStore([slug]).catch(console.error); + this.dbService.removeFromChainStore([slug]).catch((error) => chainServiceLogger.error('Error removing chain from store', error)); this.updateChainSubscription(); @@ -650,7 +653,7 @@ export class ChainService { delete chainStateMap[slug]; delete chainInfoMap[slug]; this.deleteAssetsByChain(slug); - this.dbService.removeFromChainStore([slug]).catch(console.error); + this.dbService.removeFromChainStore([slug]).catch((error) => chainServiceLogger.error('Error removing chain from store', error)); this.updateChainSubscription(); @@ -812,18 +815,18 @@ export class ChainService { if (latestChainInfo && latestChainInfo.length > 0) { const { needUpdateChainApiList, storedChainInfoList } = updateLatestChainInfo(this.dataMap, latestChainInfo); - this.dbService.bulkUpdateChainStore(storedChainInfoList).catch(console.error); + this.dbService.bulkUpdateChainStore(storedChainInfoList).catch((error) => chainServiceLogger.error('Error bulk updating chain store', error)); this.updateChainSubscription(); needUpdateChainApiList.forEach((chainInfo) => { - console.log('Updating chain API for', chainInfo.slug); - this.initApiForChain(chainInfo).catch(console.error); + chainServiceLogger.info('Updating chain API for', chainInfo.slug); + this.initApiForChain(chainInfo).catch((error) => chainServiceLogger.error('Error initializing API for chain', error)); }); this.logger.log('Finished updating latest RPC providers'); } } catch (e) { - console.error('Error fetching latest chain data'); + chainServiceLogger.error('Error fetching latest chain data', e); } } @@ -918,7 +921,7 @@ export class ChainService { if (JSON.stringify(currentTokenKeys) !== JSON.stringify(newTokenKeys)) { // Check if token keys have changed this.enablePopularTokens() .then(() => this.logger.log('Popular tokens enabled due to priority tokens change')) // Log success after enabling tokens - .catch((e) => console.error('Error enabling popular tokens:', e)); // Log error if enabling fails + .catch((e) => chainServiceLogger.error('Error enabling popular tokens', e)); // Log error if enabling fails } } @@ -934,7 +937,7 @@ export class ChainService { this.lockChainInfoMap = false; }).catch((e) => { this.lockChainInfoMap = false; - console.error('Error update latest chain data', e); + chainServiceLogger.error('Error update latest chain data', e); }); // this.fetchLatestPriceIdsData().then((latestPriceIds) => { @@ -945,19 +948,19 @@ export class ChainService { .then((latestledgerGenericAllowChains) => { this.handleLatestLedgerGenericAllowChains(latestledgerGenericAllowChains); }) - .catch(console.error); + .catch((error) => chainServiceLogger.error('Error fetching latest ledger generic allow chains', error)); this.fetchLatestPriorityTokens() .then((latestPriorityTokens) => { this.handleLatestPriorityTokens(latestPriorityTokens); }) - .catch(console.error); + .catch((error) => chainServiceLogger.error('Error fetching latest priority tokens', error)); this.fetchLatestSufficientChains() .then((latestSufficientChains) => { this.handleLatestSufficientChains(latestSufficientChains); }) - .catch(console.error); + .catch((error) => chainServiceLogger.error('Error fetching latest sufficient chains', error)); } private async initApis () { @@ -970,7 +973,7 @@ export class ChainService { try { return this.initApiForChain(chainInfo); } catch (e) { - console.error(e); + chainServiceLogger.error('Error initializing API for chain', e); return Promise.resolve(); } @@ -1033,7 +1036,7 @@ export class ChainService { // eslint-disable-next-line @typescript-eslint/no-empty-function .then(() => { }) - .catch((error) => console.error('Error connecting to the report API:', error)); + .catch((error) => chainServiceLogger.error('Error connecting to the report API', error)); } this.updateChainConnectionStatus(slug, status); @@ -1120,7 +1123,7 @@ export class ChainService { active: true, currentProvider: chainStateMap[chainSlug].currentProvider, manualTurnOff: !!chainStateMap[chainSlug].manualTurnOff - }).catch(console.error); + }).catch((error) => chainServiceLogger.error('Error upserting chain info', error)); chainStateMap[chainSlug].active = true; await this.initApiForChain(chainInfo); @@ -1159,7 +1162,7 @@ export class ChainService { active: true, currentProvider: chainStateMap[chainSlug].currentProvider, manualTurnOff: !!chainStateMap[chainSlug].manualTurnOff - }).catch(console.error); + }).catch((error) => chainServiceLogger.error('Error enabling chain', error)); chainStateMap[chainSlug].active = true; @@ -1203,7 +1206,7 @@ export class ChainService { active: false, currentProvider: chainStateMap[chainSlug].currentProvider, manualTurnOff: !preventManualTurnOff - }).catch(console.error); + }).catch((error) => chainServiceLogger.error('Error disabling chain', error)); this.updateChainStateMapSubscription(); this.lockChainInfoMap = false; @@ -1952,7 +1955,7 @@ export class ChainService { return result; } catch (e) { - console.error('Error connecting to provider', e); + chainServiceLogger.error('Error connecting to provider', e); result.success = false; result.error = _CHAIN_VALIDATION_ERROR.CONNECTION_FAILURE; @@ -2097,11 +2100,11 @@ export class ChainService { } public refreshSubstrateApi (slug: string) { - this.substrateChainHandler.recoverApi(slug).catch(console.error); + this.substrateChainHandler.recoverApi(slug).catch((error) => chainServiceLogger.error('Error refreshing substrate API', error)); } public refreshEvmApi (slug: string) { - this.evmChainHandler.recoverApi(slug).catch(console.error); + this.evmChainHandler.recoverApi(slug).catch((error) => chainServiceLogger.error('Error refreshing EVM API', error)); } public async stopAllChainApis () { diff --git a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/acala.ts b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/acala.ts index 864a6ea6614..46041523106 100644 --- a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/acala.ts +++ b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/acala.ts @@ -6,12 +6,15 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State' import { _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants'; import { _getTokenOnChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { fakeAddress } from '@subwallet/extension-base/services/earning-service/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BaseYieldStepDetail, EarningStatus, HandleYieldStepData, LiquidYieldPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RuntimeDispatchInfo, SubmitYieldJoinData, TokenBalanceRaw, TransactionData, UnstakingInfo, UnstakingStatus, YieldPoolMethodInfo, YieldPositionInfo, YieldStepType, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; import { BN, BN_TEN, BN_ZERO } from '@polkadot/util'; import BaseLiquidStakingPoolHandler from './base'; +const acalaLiquidStakingLogger = createLogger('AcalaLiquidStaking'); + interface AcalaLiquidStakingMetaItem { exchangeRate: string, timestamp: string @@ -87,7 +90,7 @@ export default class AcalaLiquidStakingPoolHandler extends BaseLiquidStakingPool }) }).then((res) => { resolve(res.json()); - }).catch(console.error); + }).catch((error) => acalaLiquidStakingLogger.error('Error in acala liquid staking', error)); }); const [_toBondPool, _totalStakingBonded, _stakingMeta] = await Promise.all([ diff --git a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost-manta.ts b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost-manta.ts index cac95530c57..7407b2c147e 100644 --- a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost-manta.ts +++ b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost-manta.ts @@ -5,10 +5,13 @@ import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/K import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { _getAssetDecimals, _getTokenOnChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { CHANNEL_ID } from '@subwallet/extension-base/services/earning-service/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BaseYieldStepDetail, HandleYieldStepData, LiquidYieldPoolInfo, OptimalYieldPath, SubmitYieldJoinData, TransactionData, YieldStepType } from '@subwallet/extension-base/types'; import BifrostLiquidStakingPoolHandler from './bifrost'; +const bifrostMantaLiquidStakingLogger = createLogger('BifrostMantaLiquidStaking'); + export interface BifrostLiquidStakingMeta { apy: string, apyBase: string, @@ -65,7 +68,7 @@ export default class BifrostMantaLiquidStakingPoolHandler extends BifrostLiquidS method: 'GET' }).then((res) => { resolve(res.json()); - }).catch(console.error); + }).catch((error) => bifrostMantaLiquidStakingLogger.error('Error in bifrost manta liquid staking', error)); }); const exchangeRatePromise = new Promise(function (resolve) { @@ -73,7 +76,7 @@ export default class BifrostMantaLiquidStakingPoolHandler extends BifrostLiquidS method: 'GET' }).then((resp) => { resolve(resp.json()); - }).catch(console.error); + }).catch((error) => bifrostMantaLiquidStakingLogger.error('Error in bifrost manta liquid staking', error)); }); const derivativeTokenInfo = this.state.getAssetBySlug(this.derivativeAssets[0]); diff --git a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost.ts b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost.ts index 718d04fced4..97af632e810 100644 --- a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost.ts +++ b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/bifrost.ts @@ -6,6 +6,7 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State' import { _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants'; import { _getAssetDecimals, _getTokenOnChainInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { CHANNEL_ID, fakeAddress } from '@subwallet/extension-base/services/earning-service/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BaseYieldStepDetail, EarningStatus, HandleYieldStepData, LiquidYieldPoolInfo, LiquidYieldPositionInfo, OptimalYieldPath, OptimalYieldPathParams, RuntimeDispatchInfo, SubmitYieldJoinData, TokenBalanceRaw, TransactionData, UnstakingInfo, UnstakingStatus, YieldPoolMethodInfo, YieldPositionInfo, YieldStepType, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; import { reformatAddress } from '@subwallet/extension-base/utils'; import BigNumber from 'bignumber.js'; @@ -14,6 +15,8 @@ import { BN, BN_ZERO } from '@polkadot/util'; import BaseLiquidStakingPoolHandler from './base'; +const bifrostLiquidStakingLogger = createLogger('BifrostLiquidStaking'); + export interface BifrostLiquidStakingMeta { apy: string, apyBase: string, @@ -97,7 +100,7 @@ export default class BifrostLiquidStakingPoolHandler extends BaseLiquidStakingPo method: 'GET' }).then((res) => { resolve(res.json()); - }).catch(console.error); + }).catch((error) => bifrostLiquidStakingLogger.error('Error in bifrost liquid staking', error)); }); const exchangeRatePromise = new Promise(function (resolve) { @@ -111,7 +114,7 @@ export default class BifrostLiquidStakingPoolHandler extends BaseLiquidStakingPo }) }).then((resp) => { resolve(resp.json()); - }).catch(console.error); + }).catch((error) => bifrostLiquidStakingLogger.error('Error in bifrost liquid staking', error)); }); const derivativeTokenInfo = this.state.getAssetBySlug(this.derivativeAssets[0]); diff --git a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/stella-swap.ts b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/stella-swap.ts index b4332bda255..f834f58a548 100644 --- a/packages/extension-base/src/services/earning-service/handlers/liquid-staking/stella-swap.ts +++ b/packages/extension-base/src/services/earning-service/handlers/liquid-staking/stella-swap.ts @@ -8,6 +8,7 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State' import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getAssetDecimals, _getContractAddressOfToken } from '@subwallet/extension-base/services/chain-service/utils'; import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { ApproveStepMetadata, BaseYieldStepDetail, BasicTxErrorType, EarningStatus, HandleYieldStepData, LiquidYieldPoolInfo, OptimalYieldPath, OptimalYieldPathParams, SubmitYieldJoinData, TokenSpendingApprovalParams, TransactionData, UnstakingInfo, UnstakingStatus, YieldPoolMethodInfo, YieldPositionInfo, YieldStepType, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; import { combineEthFee } from '@subwallet/extension-base/utils'; import { TransactionConfig } from 'web3-core'; @@ -18,6 +19,8 @@ import { BN, BN_TEN, BN_ZERO } from '@polkadot/util'; import { ST_LIQUID_TOKEN_ABI } from '../../constants'; import BaseLiquidStakingPoolHandler from './base'; +const stellaSwapLiquidStakingLogger = createLogger('StellaSwapLiquidStaking'); + export const getStellaswapLiquidStakingContract = (networkKey: string, assetAddress: string, evmApi: _EvmApi, options = {}): Contract => { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access @@ -85,7 +88,7 @@ export default class StellaSwapLiquidStakingPoolHandler extends BaseLiquidStakin method: 'GET' }).then((res) => { resolve(res.json()); - }).catch(console.error); + }).catch((error) => stellaSwapLiquidStakingLogger.error('Error in stella swap liquid staking', error)); }); const sampleTokenShare = 10 ** _getAssetDecimals(derivativeTokenInfo); @@ -298,7 +301,7 @@ export default class StellaSwapLiquidStakingPoolHandler extends BaseLiquidStakin break; } catch (e) { - console.error(e); + stellaSwapLiquidStakingLogger.error('Error in stella swap liquid staking', e); } } diff --git a/packages/extension-base/src/services/earning-service/handlers/native-staking/astar.ts b/packages/extension-base/src/services/earning-service/handlers/native-staking/astar.ts index 3173cd8aad7..dc4136cd491 100644 --- a/packages/extension-base/src/services/earning-service/handlers/native-staking/astar.ts +++ b/packages/extension-base/src/services/earning-service/handlers/native-staking/astar.ts @@ -7,6 +7,7 @@ import { ExtrinsicType, NominationInfo, UnstakingInfo } from '@subwallet/extensi import { getEarningStatusByNominations } from '@subwallet/extension-base/koni/api/staking/bonding/utils'; import { _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BaseYieldPositionInfo, BasicTxErrorType, EarningStatus, NativeYieldPoolInfo, PalletDappsStakingAccountLedger, PalletDappsStakingDappInfo, StakeCancelWithdrawalParams, SubmitJoinNativeStaking, TransactionData, UnstakingStatus, ValidatorInfo, YieldPoolInfo, YieldPoolMethodInfo, YieldPositionInfo, YieldStepBaseInfo, YieldStepType, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; import { balanceFormatter, formatNumber, isUrl, parseRawNumber, reformatAddress } from '@subwallet/extension-base/utils'; @@ -18,6 +19,8 @@ import { isEthereumAddress } from '@polkadot/util-crypto'; import BaseParaNativeStakingPoolHandler from './base-para'; +const astarStakingLogger = createLogger('AstarStaking'); + const convertAddress = (address: string) => { return isEthereumAddress(address) ? address.toLowerCase() : address; }; @@ -94,7 +97,7 @@ export default class AstarNativeStakingPoolHandler extends BaseParaNativeStaking }).then((resp) => { resolve(resp.json()); }).catch((e) => { - console.error(e); + astarStakingLogger.error('Error in astar staking', e); resolve(null); }); }); @@ -188,7 +191,7 @@ export default class AstarNativeStakingPoolHandler extends BaseParaNativeStaking method: 'GET' }).then((resp) => { resolve(resp.json()); - }).catch(console.error); + }).catch((error) => astarStakingLogger.error('Error in astar staking', error)); }); const [_allDapps, _era, _stakerInfo] = await Promise.all([ @@ -386,7 +389,7 @@ export default class AstarNativeStakingPoolHandler extends BaseParaNativeStaking method: 'GET' }).then((resp) => { resolve(resp.json()); - }).catch(console.error); + }).catch((error) => astarStakingLogger.error('Error in astar staking', error)); }); const [_era, _allDapps] = await Promise.all([ diff --git a/packages/extension-base/src/services/earning-service/handlers/native-staking/base.ts b/packages/extension-base/src/services/earning-service/handlers/native-staking/base.ts index 9c5869da5b2..37a57041f94 100644 --- a/packages/extension-base/src/services/earning-service/handlers/native-staking/base.ts +++ b/packages/extension-base/src/services/earning-service/handlers/native-staking/base.ts @@ -5,12 +5,15 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { STAKING_IDENTITY_API_SLUG } from '@subwallet/extension-base/services/earning-service/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BasicTxErrorType, EarningRewardHistoryItem, EarningRewardItem, HandleYieldStepData, OptimalYieldPath, OptimalYieldPathParams, RequestBondingSubmit, SubmitChangeValidatorStaking, SubmitJoinNativeStaking, SubmitYieldJoinData, TransactionData, ValidatorInfo, YieldPoolMethodInfo, YieldPoolType, YieldPositionInfo, YieldStepBaseInfo, YieldStepType, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; import { noop } from '@polkadot/util'; import BasePoolHandler from '../base'; +const baseNativeStakingLogger = createLogger('BaseNativeStaking'); + export default abstract class BaseNativeStakingPoolHandler extends BasePoolHandler { public readonly type = YieldPoolType.NATIVE_STAKING; protected readonly name: string; @@ -105,14 +108,14 @@ export default abstract class BaseNativeStakingPoolHandler extends BasePoolHandl } } }) - .catch(console.error); + .catch((error) => baseNativeStakingLogger.error('Error in base native staking', error)); } }) - .catch(console.error); + .catch((error) => baseNativeStakingLogger.error('Error in base native staking', error)); } return Promise.resolve(() => { - console.log('Cancel get pool reward history', requestGroupId); + baseNativeStakingLogger.debug('Cancel get pool reward history', requestGroupId); cancel = false; this.state.subscanService.cancelGroupRequest(requestGroupId); }); diff --git a/packages/extension-base/src/services/earning-service/handlers/native-staking/dtao.ts b/packages/extension-base/src/services/earning-service/handlers/native-staking/dtao.ts index f4f65f59afb..91858efd9ff 100644 --- a/packages/extension-base/src/services/earning-service/handlers/native-staking/dtao.ts +++ b/packages/extension-base/src/services/earning-service/handlers/native-staking/dtao.ts @@ -11,9 +11,12 @@ import { reformatAddress } from '@subwallet/extension-base/utils'; import BigN from 'bignumber.js'; import { BN, BN_ZERO } from '@polkadot/util'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import TaoNativeStakingPoolHandler, { DEFAULT_DTAO_MINBOND, RateSubnetData, TaoStakeInfo, TaoStakingStakeOption } from './tao'; +const dtaoStakingLogger = createLogger('DtaoStaking'); + export interface SubnetData { netuid: number; name: string; @@ -239,7 +242,7 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan this.isInit = true; } } catch (err) { - console.error(err); + dtaoStakingLogger.error('Error in dtao staking', err); this.isInit = false; } } @@ -304,12 +307,12 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan callback(data); } } catch (error) { - console.error('Error updating staking info:', error); + dtaoStakingLogger.error('Error updating staking info:', error); } }; const subscribeStakingMetadataInterval = () => { - updateStakingInfo().catch(console.error); + updateStakingInfo().catch((error) => dtaoStakingLogger.error('Error updating staking info', error)); }; subscribeStakingMetadataInterval(); @@ -412,7 +415,7 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan } }); }) - .catch(console.error); + .catch((error) => dtaoStakingLogger.error('Error in dtao staking', error)); } else { rsCallback({ ...defaultInfo, @@ -447,10 +450,10 @@ export default class SubnetTaoStakingPoolHandler extends TaoNativeStakingPoolHan await getPoolPosition(); }; - getStakingPositionInterval().catch(console.error); + getStakingPositionInterval().catch((error) => dtaoStakingLogger.error('Error in getStakingPositionInterval', error)); const intervalId = setInterval(() => { - getStakingPositionInterval().catch(console.error); + getStakingPositionInterval().catch((error) => dtaoStakingLogger.error('Error in getStakingPositionInterval', error)); }, BITTENSOR_REFRESH_STAKE_INFO); return () => { diff --git a/packages/extension-base/src/services/earning-service/handlers/native-staking/tanssi.ts b/packages/extension-base/src/services/earning-service/handlers/native-staking/tanssi.ts index 443c456eccf..0e220bbf004 100644 --- a/packages/extension-base/src/services/earning-service/handlers/native-staking/tanssi.ts +++ b/packages/extension-base/src/services/earning-service/handlers/native-staking/tanssi.ts @@ -5,6 +5,7 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr import { APIItemState, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes'; import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; import { _getAssetDecimals } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BasicTxErrorType, EarningRewardItem, EarningStatus, NativeYieldPoolInfo, NominationInfo, StakeCancelWithdrawalParams, SubmitJoinNativeStaking, TransactionData, UnstakingInfo, ValidatorInfo, YieldPoolInfo, YieldPoolMethodInfo, YieldPoolTarget, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; import { formatNumber } from '@subwallet/extension-base/utils'; import BigN from 'bignumber.js'; @@ -15,6 +16,8 @@ import { AnyJson } from '@polkadot/types/types'; import { parseIdentity } from '../../utils'; import BaseParaNativeStakingPoolHandler from './base-para'; +const tanssiStakingLogger = createLogger('TanssiStaking'); + interface SortedEligibleCandidate { candidate: string; stake: string; @@ -373,10 +376,10 @@ export default class TanssiNativeStakingPoolHandler extends BaseParaNativeStakin }); }; - fetchAndUpdate().catch(console.error); + fetchAndUpdate().catch((error) => tanssiStakingLogger.error('Error in fetchAndUpdate', error)); const intervalId = setInterval(() => { - fetchAndUpdate().catch(console.error); + fetchAndUpdate().catch((error) => tanssiStakingLogger.error('Error in fetchAndUpdate', error)); }, 30000); intervalIds.push(intervalId); diff --git a/packages/extension-base/src/services/earning-service/handlers/native-staking/tao.ts b/packages/extension-base/src/services/earning-service/handlers/native-staking/tao.ts index c9dd4fc4df7..427127a26b4 100644 --- a/packages/extension-base/src/services/earning-service/handlers/native-staking/tao.ts +++ b/packages/extension-base/src/services/earning-service/handlers/native-staking/tao.ts @@ -1,819 +1,822 @@ -// Copyright 2019-2022 @subwallet/extension-base -// SPDX-License-Identifier: Apache-2.0 - -import { _ChainInfo } from '@subwallet/chain-list/types'; -import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; -import { ExtrinsicType, NominationInfo } from '@subwallet/extension-base/background/KoniTypes'; -import { BITTENSOR_REFRESH_STAKE_APY, BITTENSOR_REFRESH_STAKE_INFO } from '@subwallet/extension-base/constants'; -import { getEarningStatusByNominations } from '@subwallet/extension-base/koni/api/staking/bonding/utils'; -import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; -import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; -import { _getAssetDecimals, _getAssetSymbol } from '@subwallet/extension-base/services/chain-service/utils'; -import BaseParaStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/native-staking/base-para'; -import { BaseYieldPositionInfo, BasicTxErrorType, EarningStatus, NativeYieldPoolInfo, OptimalYieldPath, StakeCancelWithdrawalParams, StakingTxErrorType, SubmitBittensorChangeValidatorStaking, SubmitJoinNativeStaking, TransactionData, UnstakingInfo, ValidatorInfo, YieldPoolInfo, YieldPoolMethodInfo, YieldPoolType, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; -import { ProxyServiceRoute } from '@subwallet/extension-base/types/environment'; -import { fetchFromProxyService, formatNumber, reformatAddress } from '@subwallet/extension-base/utils'; -import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache'; -import BigN from 'bignumber.js'; -import { t } from 'i18next'; -import { BehaviorSubject, combineLatest } from 'rxjs'; - -import { BN, BN_ZERO } from '@polkadot/util'; - -import { fetchPoolsData } from '../../service'; - -type Nominators = [Array<[number, number]>] - -export interface TestnetBittensorDelegateInfo { - delegateSs58: string; - take: number; - nominators: Nominators; - returnPer1000: number -} - -export interface TaoStakeInfo { - hotkey: string; - stake: string; - netuid: number; -} - -export interface TaoStakingStakeOption { - owner: string; - amount: string; - rate?: BigN; - identity?: string -} - -export interface RawDelegateState { - data: Array<{ - hotkey_name: string; - hotkey: { - ss58: string; - }; - stake: string; - }>; -} - -interface ValidatorResponse { - data: Validator[]; -} - -interface Validator { - hotkey: { - ss58: string; - }; - name: string; - global_nominators: number; - validator_return_per_day: string; - nominator_return_per_day: string; - stake: string; - validator_stake: string; - take: string; - root_stake: string; - global_weighted_stake: string; - weighted_root_stake: string; - global_alpha_stake_as_tao: string; -} - -interface ValidatorAprResponse { - data: ValidatorApr[]; -} - -interface ValidatorApr { - hotkey: { - ss58: string; - }, - name: string; - netuid: number; - thirty_day_apy: string; -} - -export interface RateSubnetData { - netuid: number; - taoIn: string; - alphaIn: string; - alphaOut: string; -} - -interface SubnetRateFeeResponse { - data: SubnetFeeRate[]; -} - -interface SubnetFeeRate { - netuid: number; - fee_rate: string; -} - -const DEFAULT_BITTENSOR_SLIPPAGE = 0.005; - -export const DEFAULT_DTAO_MINBOND = '21000000'; -/* Fetch data */ -export class BittensorCache { - private static instance: BittensorCache | null = null; - private cache: ValidatorResponse | null = null; - private cacheTimeout: NodeJS.Timeout | null = null; - private promise: Promise | null = null; - - // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function - private constructor () {} - - public static getInstance (): BittensorCache { - if (!BittensorCache.instance) { - BittensorCache.instance = new BittensorCache(); - } - - return BittensorCache.instance; - } - - public async get (): Promise { - if (this.cache) { - return this.cache; - } - - if (this.promise) { - return this.promise; - } - - this.promise = this.fetchData(); - - return this.promise; - } - - private async fetchData (): Promise { - try { - const fetchData = await fetchStaticCache<{ data: Record }>( - 'earning/dtao/validator.json', - { data: {} } - ); - - const validators = Object.values(fetchData.data); - - const data = { - data: validators.filter((validator) => parseFloat(validator.root_stake) > 0) - }; - - this.cache = data; - this.promise = null; - - if (this.cacheTimeout) { - clearTimeout(this.cacheTimeout); - } - - this.cacheTimeout = setTimeout(() => { - this.fetchData() - .then((newData) => { - if (newData.data.length > 0) { - this.cache = newData; - } - }) - .catch(console.error); - }, 60 * 1000); // Cache 1 minute - - return data; - } catch (error) { - console.error(error); - this.promise = null; - - return this.cache || { data: [] }; - } - } - - public async fetchApr (netuid: number): Promise { - try { - const resp = await fetchFromProxyService(ProxyServiceRoute.BITTENSOR, `/dtao/validator/yield/latest/v1?netuid=${netuid}&limit=100&order=thirty_day_apy_desc`, { - method: 'GET', - headers: { 'Content-Type': 'application/json' } - }); - - const rawData = await resp.json() as ValidatorAprResponse; - - // Some subnets not return data, ensure the structure is consistent by returning an empty array - return Array.isArray(rawData.data) ? rawData : { data: [] }; - } catch (error) { - console.error(error); - - return { data: [] }; - } - } - - public async fetchSubnetFeeRate (netuid: number): Promise { - try { - const resp = await fetchFromProxyService( - ProxyServiceRoute.BITTENSOR, - '/subnet/latest/v1', - { - method: 'GET', - headers: { 'Content-Type': 'application/json' } - } - ); - - const rawData = await resp.json() as SubnetRateFeeResponse; - - const subnet = rawData.data.find((item) => item.netuid === netuid); - - return subnet?.fee_rate ?? '0.0005'; - } catch (error) { - console.error(error); - - return '0.0005'; // Default fee rate if fetch fails - } - } -} - -// export async function fetchTaoDelegateState (address: string): Promise { -// const apiKey = bittensorApiKey(); - -// return new Promise(function (resolve) { -// fetch(`https://api.taostats.io/api/stake_balance/latest/v1?coldkey=${address}`, { -// method: 'GET', -// headers: { -// 'Content-Type': 'application/json', -// Authorization: `${apiKey}` -// } -// }).then((resp) => { -// resolve(resp.json()); -// }).catch(console.error); -// }); -// } - -/* Fetch data */ - -// const testnetDelegate = { -// '5G6wdAdS7hpBuH1tjuZDhpzrGw9Wf71WEVakDCxHDm1cxEQ2': { -// name: '0x436c6f776e4e616d65f09fa4a1', -// url: 'https://example.com ', -// image: 'https://example.com/image.png', -// discord: '0xe28094446973636f7264', -// description: 'This is an example identity.', -// additional: '' -// } -// }; - -export const getAlphaToTaoRate = async (substrateApi: _SubstrateApi, netuid: number): Promise => { - const subnetInfo = (await substrateApi.api.call.subnetInfoRuntimeApi.getDynamicInfo(netuid)).toJSON() as RateSubnetData | undefined; - - if (!subnetInfo) { - return '1'; - } - - const taoIn = subnetInfo.taoIn ? new BigN(subnetInfo.taoIn) : new BigN(0); - const alphaIn = subnetInfo.alphaIn ? new BigN(subnetInfo.alphaIn) : new BigN(0); - - return netuid === 0 || alphaIn.lte(0) ? '1' : taoIn.dividedBy(alphaIn).toString(); -}; - -export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHandler { - override readonly availableMethod: YieldPoolMethodInfo = { - join: true, - defaultUnstake: true, - fastUnstake: false, - cancelUnstake: false, - withdraw: false, - claimReward: false, - changeValidator: true - }; - - protected bittensorCache: BittensorCache; - - protected async getMinBond (netuid?: number): Promise { - // @ts-ignore - if (this.type === YieldPoolType.SUBNET_STAKING) { - if (!netuid) { - return new BigN(DEFAULT_DTAO_MINBOND); - } - - const subnetSlug = `${this.slug}__subnet_${netuid.toString().padStart(2, '0')}`; - - const cachedPool = await this.getPoolInfo(subnetSlug); - - if (cachedPool?.metadata?.minValidate) { - return new BigN(cachedPool.metadata.minValidate); - } - - // If can't get from cached -> get data online - const onlineData = await fetchPoolsData(); - const onlinePool = onlineData[subnetSlug]; - - return new BigN(onlinePool?.metadata?.minValidate || DEFAULT_DTAO_MINBOND); - } - - const cachedPool = await this.getPoolInfo(this.slug); - - if (cachedPool?.metadata?.minValidate || cachedPool?.statistic?.earningThreshold?.join) { - return new BigN(cachedPool.metadata?.minValidate || cachedPool.statistic?.earningThreshold?.join || 0); - } - - // If can get from cached -> get data online - const onlineData = await fetchPoolsData(); - const onlinePool = onlineData[this.slug]; - - return new BigN(onlinePool?.metadata?.minValidate || onlinePool?.statistic?.earningThreshold?.join || 0); - } - - constructor (state: KoniState, chain: string) { - super(state, chain); - this.bittensorCache = BittensorCache.getInstance(); - } - - /* Unimplemented function */ - public override handleYieldWithdraw (address: string, unstakingInfo: UnstakingInfo): Promise { - return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED)); - } - - public override handleYieldCancelUnstake (params: StakeCancelWithdrawalParams): Promise { - return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED)); - } - /* Unimplemented function */ - - public override get maintainBalance (): string { - const ed = new BigN(this.nativeToken.minAmount || '0'); - const calculateMaintainBalance = new BigN(15).multipliedBy(ed).dividedBy(10); - - const maintainBalance = calculateMaintainBalance; - - return maintainBalance.toString(); - } - - /* Subscribe pool info */ - - async subscribePoolInfo (callback: (data: YieldPoolInfo) => void): Promise { - let cancel = false; - const substrateApi = await this.substrateApi.isReady; - - const aprSubject = new BehaviorSubject(0); - - const fetchAPR = async () => { - try { - const _topValidator = await this.bittensorCache.fetchApr(0); - const validators = _topValidator.data; - const highestApr = validators?.[0]; - - const apr = this.chain === 'bittensor' ? Number(highestApr?.thirty_day_apy || 0) * 100 : 0; - - aprSubject.next(apr); - } catch (e) { - console.error('Fetch APR error:', e); - } - }; - - await fetchAPR(); - - const interval = setInterval(() => { - fetchAPR().catch(console.error); - }, BITTENSOR_REFRESH_STAKE_APY); - - const rxSubnetTAO = substrateApi.api.rx.query.subtensorModule.subnetTAO(0); - const rxMinDelegatorStake = substrateApi.api.rx.query.subtensorModule.nominatorMinRequiredStake(); - const rxMaxValidators = substrateApi.api.rx.query.subtensorModule.maxAllowedValidators(0); - - const subscription = combineLatest([rxMinDelegatorStake, rxMaxValidators, rxSubnetTAO, aprSubject]).subscribe({ - next: ([minDelegatorStake, maxValidators, taoIn, apr]) => { - if (cancel) { - return; - } - - try { - const bnTaoIn = new BigN(taoIn.toString()); - const bnMinStake = new BigN(minDelegatorStake.toString()); - const minStake = bnMinStake.toString(); - const data: NativeYieldPoolInfo = { - ...this.baseInfo, - type: this.type, - metadata: { - ...this.metadataInfo, - description: this.getDescription(formatNumber(bnMinStake, _getAssetDecimals(this.nativeToken))), - minValidate: minStake - }, - statistic: { - assetEarning: [{ slug: this.nativeToken.slug }], - maxCandidatePerFarmer: Number(maxValidators.toString()), - maxWithdrawalRequestPerFarmer: 1, - earningThreshold: { - join: minStake, - defaultUnstake: '0', - fastUnstake: '0' - }, - eraTime: 24, - era: 0, - unstakingPeriod: 1.2, - tvl: bnTaoIn.toString(), - totalApy: apr - } - }; - - callback(data); - } catch (err) { - console.error(err); - } - } - }); - - return () => { - cancel = true; - aprSubject.complete(); - subscription.unsubscribe(); - clearInterval(interval); - }; - } - - /* Subscribe pool position */ - - protected parseNominatorMetadataBase (chainInfo: _ChainInfo, delegatorState: TaoStakingStakeOption[], minBond: string, applyRate = false): Omit { - const nominationList: NominationInfo[] = []; - let allActiveStake = BN_ZERO; - - for (const delegate of delegatorState) { - const stake = new BigN(delegate.amount); - const originActiveStake = applyRate ? stake.multipliedBy(delegate.rate || 1).toFixed(0) : stake.toFixed(0); - const bnActiveStake = new BN(originActiveStake); - - if (bnActiveStake.gt(BN_ZERO)) { - allActiveStake = allActiveStake.add(bnActiveStake); - - nominationList.push({ - status: EarningStatus.EARNING_REWARD, - chain: chainInfo.slug, - validatorAddress: delegate.owner, - activeStake: delegate.amount, - validatorMinStake: minBond, - validatorIdentity: delegate.identity, - ...(applyRate ? { originActiveStake } : {}) - }); - } - } - - const stakingStatus = getEarningStatusByNominations(allActiveStake, nominationList); - - return { - status: stakingStatus, - balanceToken: this.nativeToken.slug, - totalStake: allActiveStake.toString(), - activeStake: allActiveStake.toString(), - unstakeBalance: '0', - isBondedBefore: true, - nominations: nominationList, - unstakings: [] - } as unknown as YieldPositionInfo; - } - - async parseNominatorMetadata (chainInfo: _ChainInfo, delegatorState: TaoStakingStakeOption[]): Promise> { - const bnMinBond = await this.getMinBond(); - - return this.parseNominatorMetadataBase(chainInfo, delegatorState, bnMinBond.toString()); - } - - override async subscribePoolPosition (useAddresses: string[], rsCallback: (rs: YieldPositionInfo) => void): Promise { - let cancel = false; - const substrateApi = await this.substrateApi.isReady; - const defaultInfo = this.baseInfo; - const chainInfo = this.chainInfo; - const _delegateInfo = await this.bittensorCache.get(); - - const getPoolPosition = async () => { - const rawDelegateStateInfos = await Promise.all( - useAddresses.map(async (address) => (await substrateApi.api.call.stakeInfoRuntimeApi.getStakeInfoForColdkey(address)).toJSON()) - ); - - if (rawDelegateStateInfos && rawDelegateStateInfos.length > 0) { - rawDelegateStateInfos.forEach((rawDelegateStateInfo, i) => { - const owner = reformatAddress(useAddresses[i], 42); - const delegatorState: TaoStakingStakeOption[] = []; - let bnTotalBalance = BN_ZERO; - - const delegateStateInfo = rawDelegateStateInfo as unknown as TaoStakeInfo[]; - - const totalDelegate: Record = {}; - - for (const delegate of delegateStateInfo) { - const hotkey = delegate.hotkey; - const netuid = delegate.netuid; - const stake = new BigN(delegate.stake); - - if (netuid === 0) { - const taoStake = stake.toFixed(0); - - if (totalDelegate[hotkey]) { - totalDelegate[hotkey] = new BigN(totalDelegate[hotkey]).plus(taoStake).toFixed(); - } else { - totalDelegate[hotkey] = taoStake; - } - } - } - - for (const hotkey in totalDelegate) { - bnTotalBalance = bnTotalBalance.add(new BN(totalDelegate[hotkey])); - let identity = ''; - - if (_delegateInfo) { - const delegateInfo = _delegateInfo.data.find((info) => info.hotkey.ss58 === hotkey); - - identity = delegateInfo ? delegateInfo.name : ''; - } - - delegatorState.push({ - owner: hotkey, - amount: totalDelegate[hotkey], - identity: identity - }); - } - - if (delegateStateInfo && delegateStateInfo.length > 0) { - this.parseNominatorMetadata(chainInfo, delegatorState) - .then((nominatorMetadata) => { - rsCallback({ - ...defaultInfo, - ...nominatorMetadata, - address: owner, - type: this.type - }); - }) - .catch(console.error); - } else { - rsCallback({ - ...defaultInfo, - type: this.type, - address: owner, - balanceToken: this.nativeToken.slug, - totalStake: '0', - activeStake: '0', - unstakeBalance: '0', - status: EarningStatus.NOT_STAKING, - isBondedBefore: false, - nominations: [], - unstakings: [] - }); - } - }); - } - }; - - const getStakingPositionInterval = async () => { - if (cancel) { - return; - } - - await getPoolPosition(); - }; - - getStakingPositionInterval().catch(console.error); - - const intervalId = setInterval(() => { - getStakingPositionInterval().catch(console.error); - }, BITTENSOR_REFRESH_STAKE_INFO); - - return () => { - cancel = true; - clearInterval(intervalId); - }; - } - - // Because not have subscan api - override async checkAccountHaveStake (useAddresses: string[]): Promise { - return Promise.resolve([]); - } - - /* Subscribe pool position */ - - /* Get pool targets */ - // eslint-disable-next-line @typescript-eslint/require-await - private async getDevnetPoolTargets (netuid?: number): Promise { - const testnetDelegate = (await this.substrateApi.api.call.delegateInfoRuntimeApi.getDelegates()).toJSON() as unknown as TestnetBittensorDelegateInfo[]; - const bnMinBond = await this.getMinBond(netuid); - - const filteredDelegates = testnetDelegate.filter((delegate) => { - return delegate.returnPer1000 !== 0; - }); - - return filteredDelegates.map((delegate) => ({ - address: delegate.delegateSs58, - totalStake: '0', - ownStake: '0', - otherStake: '0', - minBond: bnMinBond.toString(), - nominatorCount: delegate.nominators.length, - commission: delegate.take / 1000, - blocked: false, - isVerified: false, - chain: this.chain, - isCrowded: false - }) as unknown as ValidatorInfo); - } - - private async getMainnetPoolTargets (netuid: number): Promise { - const _topValidator = await this.bittensorCache.get(); - - const topValidator = _topValidator; - const bnMinBond = await this.getMinBond(); - const validatorList = topValidator.data; - - const aprResponse = await this.bittensorCache.fetchApr(netuid); - const aprMap: Record = {}; - - aprResponse.data.forEach((item) => { - aprMap[item.hotkey.ss58] = item.thirty_day_apy; - }); - - const results = await Promise.all( - validatorList.map((validator) => { - const address = validator.hotkey.ss58; - // With bittensor we use total weight, root weight and alpha staked insted of total stake, own stake and other stake - const bnTotalWeightStake = new BigN(validator.global_weighted_stake); - const bnRootWeightStake = new BigN(validator.weighted_root_stake); - const bnAlphaStake = new BigN(validator.global_alpha_stake_as_tao); - - const nominatorCount = validator.global_nominators; - const commission = validator.take; - const roundedCommission = (parseFloat(commission) * 100).toFixed(0); - - const apr = aprMap[address]; - const expectedReturn = apr ? new BigN(apr).multipliedBy(100).toFixed(2) : '0'; - - const name = validator.name || address; - - return { - address: address, - totalStake: bnTotalWeightStake.toString(), - ownStake: bnRootWeightStake.toString(), - otherStake: bnAlphaStake.toString(), - minBond: bnMinBond.toString(), - nominatorCount: nominatorCount, - commission: roundedCommission, - expectedReturn: expectedReturn, - blocked: false, - isVerified: false, - chain: this.chain, - isCrowded: false, - identity: name - } as unknown as ValidatorInfo; - }) - ); - - return results; - } - - async getPoolTargets (netuid?: number): Promise { - if (this.chain === 'bittensor') { - return this.getMainnetPoolTargets(netuid ?? 0); - } else { - return this.getDevnetPoolTargets(netuid); - } - } - - /* Get pool targets */ - - /* Join pool action */ - - override async createJoinExtrinsic ( - data: SubmitJoinNativeStaking, - positionInfo?: YieldPositionInfo, - bondDest = 'Staked' - ): Promise<[TransactionData, YieldTokenBaseInfo]> { - const { amount, selectedValidators: targetValidators, subnetData } = data; - - const chainApi = await this.substrateApi.isReady; - const binaryAmount = new BigN(amount); - const selectedValidatorInfo = targetValidators[0]; - const hotkey = selectedValidatorInfo.address; - - const netuid = subnetData?.netuid ?? 0; - const slippage = subnetData?.slippage ?? DEFAULT_BITTENSOR_SLIPPAGE; - - const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid)); - const limitPrice = alphaToTaoPrice - .multipliedBy(10 ** _getAssetDecimals(this.nativeToken)) - .multipliedBy(1 + slippage); - - const BNlimitPrice = new BigN(limitPrice.integerValue(BigN.ROUND_CEIL).toFixed()); - - const extrinsic = chainApi.api.tx.subtensorModule.addStakeLimit( - hotkey, - netuid, - binaryAmount.toFixed(), - BNlimitPrice.toFixed(), - false - ); - - return [extrinsic, { slug: this.nativeToken.slug, amount: '0' }]; - } - - // Validate for case stake more - public override async validateYieldJoin (data: SubmitJoinNativeStaking, path: OptimalYieldPath): Promise { - const baseErrors = await super.validateYieldJoin(data, path); - - if (baseErrors.length > 0) { - return baseErrors; - } - - const { amount, subnetData } = data; - - const bnMinStake = await this.getMinBond(subnetData?.netuid); - - if (new BigN(amount).lt(bnMinStake)) { - return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.insufficientStakeToEarn', { replace: { bnMinStake: formatNumber(bnMinStake, _getAssetDecimals(this.nativeToken)), symbol: _getAssetSymbol(this.nativeToken) } }))]; - } - - return baseErrors; - } - - /* Join pool action */ - - /* Leave pool action */ - - override async handleYieldUnstake (amount: string, address: string, selectedTarget?: string, netuid = 0, slippage: number = DEFAULT_BITTENSOR_SLIPPAGE): Promise<[ExtrinsicType, TransactionData]> { - const apiPromise = await this.substrateApi.isReady; - - if (!selectedTarget) { - return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS)); - } - - const binaryAmount = new BigN(amount); - - const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid)); - const limitPrice = alphaToTaoPrice - .multipliedBy(10 ** _getAssetDecimals(this.nativeToken)) - .multipliedBy(1 - slippage); - - const BNlimitPrice = new BigN(limitPrice.integerValue(BigN.ROUND_CEIL).toFixed()); - - const extrinsic = apiPromise.api.tx.subtensorModule.removeStakeLimit( - selectedTarget, - netuid, - binaryAmount.toFixed(), - BNlimitPrice.toFixed(), - false - ); - - return [ExtrinsicType.STAKING_UNBOND, extrinsic]; - } - - public override async validateYieldLeave (amount: string, address: string, fastLeave: boolean, selectedTarget?: string, slug?: string, poolInfo?: YieldPoolInfo): Promise { - const baseErrors = await super.validateYieldLeave(amount, address, fastLeave, selectedTarget, slug); - - if (baseErrors.length > 0) { - return baseErrors; - } - - if (!poolInfo) { - return [new TransactionError(BasicTxErrorType.INVALID_PARAMS)]; - } - - const netuid = poolInfo.metadata.subnetData?.netuid; - const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid || 0)); - - const minDelegatorStake = await this.getMinBond(netuid); - - const minUnstake = minDelegatorStake.dividedBy(alphaToTaoPrice); - - if (new BigN(amount).lt(minUnstake)) { - return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.unstakeAmountTooLow', { replace: { bnMinUnstake: formatNumber(minUnstake, _getAssetDecimals(this.nativeToken)), symbol: poolInfo.metadata.subnetData?.subnetSymbol || _getAssetSymbol(this.nativeToken) } }))]; - } - - return baseErrors; - } - - /* Leave pool action */ - - /* Change validator */ - override async handleChangeEarningValidator (data: SubmitBittensorChangeValidatorStaking): Promise { - const chainApi = await this.substrateApi.isReady; - const { amount, maxAmount, metadata, originValidator, selectedValidators: targetValidators, subnetData } = data; - - if (!originValidator) { - return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS)); - } - - const netuid = subnetData?.netuid || 0; - const selectedValidatorInfo = targetValidators[0]; - const destValidator = selectedValidatorInfo.address; - - if (new BigN(amount).lte(0)) { - return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.amountMustBeGreaterThanZero'))); - } - - if (originValidator === destValidator) { - return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.fromValidatorSameAsTo'))); - } - - const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid)); - const bnMinStake = await this.getMinBond(netuid); - const minUnstake = bnMinStake.dividedBy(alphaToTaoPrice); - - const formattedMinUnstake = minUnstake.dividedBy(1000000).integerValue(BigN.ROUND_CEIL).dividedBy(1000); - - const bnMinMoveStake = formattedMinUnstake.multipliedBy(10 ** _getAssetDecimals(this.nativeToken)); - - if (new BigN(amount).lt(bnMinMoveStake)) { - return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.moveStakeAmountTooLow', { replace: { bnMinMoveStake: formattedMinUnstake.toString(), symbol: metadata?.subnetSymbol || '' } }))); - } - - // Avoid remaining amount too low -> can't do anything with that amount - if (!(maxAmount === amount) && new BigN(maxAmount).minus(new BigN(amount)).lt(bnMinMoveStake)) { - return Promise.reject(new TransactionError(StakingTxErrorType.REMAINING_AMOUNT_TOO_LOW, - t('bg.EARNING.services.service.earning.nativeStaking.tao.remainingStakeBelowMinimumWarning', { replace: { maxAmount: formatNumber(maxAmount, _getAssetDecimals(this.nativeToken)), subnetSymbol: metadata?.subnetSymbol || _getAssetSymbol(this.nativeToken) } }))); - } - - const extrinsic = chainApi.api.tx.subtensorModule.moveStake(originValidator, destValidator, netuid, netuid, amount); - - return extrinsic; - } -} +// Copyright 2019-2022 @subwallet/extension-base +// SPDX-License-Identifier: Apache-2.0 + +import { _ChainInfo } from '@subwallet/chain-list/types'; +import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError'; +import { ExtrinsicType, NominationInfo } from '@subwallet/extension-base/background/KoniTypes'; +import { BITTENSOR_REFRESH_STAKE_APY, BITTENSOR_REFRESH_STAKE_INFO } from '@subwallet/extension-base/constants'; +import { getEarningStatusByNominations } from '@subwallet/extension-base/koni/api/staking/bonding/utils'; +import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; +import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types'; +import { _getAssetDecimals, _getAssetSymbol } from '@subwallet/extension-base/services/chain-service/utils'; +import BaseParaStakingPoolHandler from '@subwallet/extension-base/services/earning-service/handlers/native-staking/base-para'; +import { BaseYieldPositionInfo, BasicTxErrorType, EarningStatus, NativeYieldPoolInfo, OptimalYieldPath, StakeCancelWithdrawalParams, StakingTxErrorType, SubmitBittensorChangeValidatorStaking, SubmitJoinNativeStaking, TransactionData, UnstakingInfo, ValidatorInfo, YieldPoolInfo, YieldPoolMethodInfo, YieldPoolType, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types'; +import { ProxyServiceRoute } from '@subwallet/extension-base/types/environment'; +import { fetchFromProxyService, formatNumber, reformatAddress } from '@subwallet/extension-base/utils'; +import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache'; +import BigN from 'bignumber.js'; +import { t } from 'i18next'; +import { BehaviorSubject, combineLatest } from 'rxjs'; + +import { BN, BN_ZERO } from '@polkadot/util'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +import { fetchPoolsData } from '../../service'; + +const taoStakingLogger = createLogger('TaoStaking'); + +type Nominators = [Array<[number, number]>] + +export interface TestnetBittensorDelegateInfo { + delegateSs58: string; + take: number; + nominators: Nominators; + returnPer1000: number +} + +export interface TaoStakeInfo { + hotkey: string; + stake: string; + netuid: number; +} + +export interface TaoStakingStakeOption { + owner: string; + amount: string; + rate?: BigN; + identity?: string +} + +export interface RawDelegateState { + data: Array<{ + hotkey_name: string; + hotkey: { + ss58: string; + }; + stake: string; + }>; +} + +interface ValidatorResponse { + data: Validator[]; +} + +interface Validator { + hotkey: { + ss58: string; + }; + name: string; + global_nominators: number; + validator_return_per_day: string; + nominator_return_per_day: string; + stake: string; + validator_stake: string; + take: string; + root_stake: string; + global_weighted_stake: string; + weighted_root_stake: string; + global_alpha_stake_as_tao: string; +} + +interface ValidatorAprResponse { + data: ValidatorApr[]; +} + +interface ValidatorApr { + hotkey: { + ss58: string; + }, + name: string; + netuid: number; + thirty_day_apy: string; +} + +export interface RateSubnetData { + netuid: number; + taoIn: string; + alphaIn: string; + alphaOut: string; +} + +interface SubnetRateFeeResponse { + data: SubnetFeeRate[]; +} + +interface SubnetFeeRate { + netuid: number; + fee_rate: string; +} + +const DEFAULT_BITTENSOR_SLIPPAGE = 0.005; + +export const DEFAULT_DTAO_MINBOND = '21000000'; +/* Fetch data */ +export class BittensorCache { + private static instance: BittensorCache | null = null; + private cache: ValidatorResponse | null = null; + private cacheTimeout: NodeJS.Timeout | null = null; + private promise: Promise | null = null; + + // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function + private constructor () {} + + public static getInstance (): BittensorCache { + if (!BittensorCache.instance) { + BittensorCache.instance = new BittensorCache(); + } + + return BittensorCache.instance; + } + + public async get (): Promise { + if (this.cache) { + return this.cache; + } + + if (this.promise) { + return this.promise; + } + + this.promise = this.fetchData(); + + return this.promise; + } + + private async fetchData (): Promise { + try { + const fetchData = await fetchStaticCache<{ data: Record }>( + 'earning/dtao/validator.json', + { data: {} } + ); + + const validators = Object.values(fetchData.data); + + const data = { + data: validators.filter((validator) => parseFloat(validator.root_stake) > 0) + }; + + this.cache = data; + this.promise = null; + + if (this.cacheTimeout) { + clearTimeout(this.cacheTimeout); + } + + this.cacheTimeout = setTimeout(() => { + this.fetchData() + .then((newData) => { + if (newData.data.length > 0) { + this.cache = newData; + } + }) + .catch((error) => taoStakingLogger.error('Error fetching delegate state', error)); + }, 60 * 1000); // Cache 1 minute + + return data; + } catch (error) { + taoStakingLogger.error('Error fetching delegate state', error); + this.promise = null; + + return this.cache || { data: [] }; + } + } + + public async fetchApr (netuid: number): Promise { + try { + const resp = await fetchFromProxyService(ProxyServiceRoute.BITTENSOR, `/dtao/validator/yield/latest/v1?netuid=${netuid}&limit=100&order=thirty_day_apy_desc`, { + method: 'GET', + headers: { 'Content-Type': 'application/json' } + }); + + const rawData = await resp.json() as ValidatorAprResponse; + + // Some subnets not return data, ensure the structure is consistent by returning an empty array + return Array.isArray(rawData.data) ? rawData : { data: [] }; + } catch (error) { + taoStakingLogger.error('Error fetching delegate state by subnet', error); + + return { data: [] }; + } + } + + public async fetchSubnetFeeRate (netuid: number): Promise { + try { + const resp = await fetchFromProxyService( + ProxyServiceRoute.BITTENSOR, + '/subnet/latest/v1', + { + method: 'GET', + headers: { 'Content-Type': 'application/json' } + } + ); + + const rawData = await resp.json() as SubnetRateFeeResponse; + + const subnet = rawData.data.find((item) => item.netuid === netuid); + + return subnet?.fee_rate ?? '0.0005'; + } catch (error) { + taoStakingLogger.error('Error fetching subnet fee rate', error); + + return '0.0005'; // Default fee rate if fetch fails + } + } +} + +// export async function fetchTaoDelegateState (address: string): Promise { +// const apiKey = bittensorApiKey(); + +// return new Promise(function (resolve) { +// fetch(`https://api.taostats.io/api/stake_balance/latest/v1?coldkey=${address}`, { +// method: 'GET', +// headers: { +// 'Content-Type': 'application/json', +// Authorization: `${apiKey}` +// } +// }).then((resp) => { +// resolve(resp.json()); +// }).catch(console.error); +// }); +// } + +/* Fetch data */ + +// const testnetDelegate = { +// '5G6wdAdS7hpBuH1tjuZDhpzrGw9Wf71WEVakDCxHDm1cxEQ2': { +// name: '0x436c6f776e4e616d65f09fa4a1', +// url: 'https://example.com ', +// image: 'https://example.com/image.png', +// discord: '0xe28094446973636f7264', +// description: 'This is an example identity.', +// additional: '' +// } +// }; + +export const getAlphaToTaoRate = async (substrateApi: _SubstrateApi, netuid: number): Promise => { + const subnetInfo = (await substrateApi.api.call.subnetInfoRuntimeApi.getDynamicInfo(netuid)).toJSON() as RateSubnetData | undefined; + + if (!subnetInfo) { + return '1'; + } + + const taoIn = subnetInfo.taoIn ? new BigN(subnetInfo.taoIn) : new BigN(0); + const alphaIn = subnetInfo.alphaIn ? new BigN(subnetInfo.alphaIn) : new BigN(0); + + return netuid === 0 || alphaIn.lte(0) ? '1' : taoIn.dividedBy(alphaIn).toString(); +}; + +export default class TaoNativeStakingPoolHandler extends BaseParaStakingPoolHandler { + override readonly availableMethod: YieldPoolMethodInfo = { + join: true, + defaultUnstake: true, + fastUnstake: false, + cancelUnstake: false, + withdraw: false, + claimReward: false, + changeValidator: true + }; + + protected bittensorCache: BittensorCache; + + protected async getMinBond (netuid?: number): Promise { + // @ts-ignore + if (this.type === YieldPoolType.SUBNET_STAKING) { + if (!netuid) { + return new BigN(DEFAULT_DTAO_MINBOND); + } + + const subnetSlug = `${this.slug}__subnet_${netuid.toString().padStart(2, '0')}`; + + const cachedPool = await this.getPoolInfo(subnetSlug); + + if (cachedPool?.metadata?.minValidate) { + return new BigN(cachedPool.metadata.minValidate); + } + + // If can't get from cached -> get data online + const onlineData = await fetchPoolsData(); + const onlinePool = onlineData[subnetSlug]; + + return new BigN(onlinePool?.metadata?.minValidate || DEFAULT_DTAO_MINBOND); + } + + const cachedPool = await this.getPoolInfo(this.slug); + + if (cachedPool?.metadata?.minValidate || cachedPool?.statistic?.earningThreshold?.join) { + return new BigN(cachedPool.metadata?.minValidate || cachedPool.statistic?.earningThreshold?.join || 0); + } + + // If can get from cached -> get data online + const onlineData = await fetchPoolsData(); + const onlinePool = onlineData[this.slug]; + + return new BigN(onlinePool?.metadata?.minValidate || onlinePool?.statistic?.earningThreshold?.join || 0); + } + + constructor (state: KoniState, chain: string) { + super(state, chain); + this.bittensorCache = BittensorCache.getInstance(); + } + + /* Unimplemented function */ + public override handleYieldWithdraw (address: string, unstakingInfo: UnstakingInfo): Promise { + return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED)); + } + + public override handleYieldCancelUnstake (params: StakeCancelWithdrawalParams): Promise { + return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED)); + } + /* Unimplemented function */ + + public override get maintainBalance (): string { + const ed = new BigN(this.nativeToken.minAmount || '0'); + const calculateMaintainBalance = new BigN(15).multipliedBy(ed).dividedBy(10); + + const maintainBalance = calculateMaintainBalance; + + return maintainBalance.toString(); + } + + /* Subscribe pool info */ + + async subscribePoolInfo (callback: (data: YieldPoolInfo) => void): Promise { + let cancel = false; + const substrateApi = await this.substrateApi.isReady; + + const aprSubject = new BehaviorSubject(0); + + const fetchAPR = async () => { + try { + const _topValidator = await this.bittensorCache.fetchApr(0); + const validators = _topValidator.data; + const highestApr = validators?.[0]; + + const apr = this.chain === 'bittensor' ? Number(highestApr?.thirty_day_apy || 0) * 100 : 0; + + aprSubject.next(apr); + } catch (e) { + taoStakingLogger.error('Fetch APR error:', e); + } + }; + + await fetchAPR(); + + const interval = setInterval(() => { + fetchAPR().catch((error) => taoStakingLogger.error('Error fetching APR', error)); + }, BITTENSOR_REFRESH_STAKE_APY); + + const rxSubnetTAO = substrateApi.api.rx.query.subtensorModule.subnetTAO(0); + const rxMinDelegatorStake = substrateApi.api.rx.query.subtensorModule.nominatorMinRequiredStake(); + const rxMaxValidators = substrateApi.api.rx.query.subtensorModule.maxAllowedValidators(0); + + const subscription = combineLatest([rxMinDelegatorStake, rxMaxValidators, rxSubnetTAO, aprSubject]).subscribe({ + next: ([minDelegatorStake, maxValidators, taoIn, apr]) => { + if (cancel) { + return; + } + + try { + const bnTaoIn = new BigN(taoIn.toString()); + const bnMinStake = new BigN(minDelegatorStake.toString()); + const minStake = bnMinStake.toString(); + const data: NativeYieldPoolInfo = { + ...this.baseInfo, + type: this.type, + metadata: { + ...this.metadataInfo, + description: this.getDescription(formatNumber(bnMinStake, _getAssetDecimals(this.nativeToken))), + minValidate: minStake + }, + statistic: { + assetEarning: [{ slug: this.nativeToken.slug }], + maxCandidatePerFarmer: Number(maxValidators.toString()), + maxWithdrawalRequestPerFarmer: 1, + earningThreshold: { + join: minStake, + defaultUnstake: '0', + fastUnstake: '0' + }, + eraTime: 24, + era: 0, + unstakingPeriod: 1.2, + tvl: bnTaoIn.toString(), + totalApy: apr + } + }; + + callback(data); + } catch (err) { + taoStakingLogger.error('Error in getStakingPositionInterval', err); + } + } + }); + + return () => { + cancel = true; + aprSubject.complete(); + subscription.unsubscribe(); + clearInterval(interval); + }; + } + + /* Subscribe pool position */ + + protected parseNominatorMetadataBase (chainInfo: _ChainInfo, delegatorState: TaoStakingStakeOption[], minBond: string, applyRate = false): Omit { + const nominationList: NominationInfo[] = []; + let allActiveStake = BN_ZERO; + + for (const delegate of delegatorState) { + const stake = new BigN(delegate.amount); + const originActiveStake = applyRate ? stake.multipliedBy(delegate.rate || 1).toFixed(0) : stake.toFixed(0); + const bnActiveStake = new BN(originActiveStake); + + if (bnActiveStake.gt(BN_ZERO)) { + allActiveStake = allActiveStake.add(bnActiveStake); + + nominationList.push({ + status: EarningStatus.EARNING_REWARD, + chain: chainInfo.slug, + validatorAddress: delegate.owner, + activeStake: delegate.amount, + validatorMinStake: minBond, + validatorIdentity: delegate.identity, + ...(applyRate ? { originActiveStake } : {}) + }); + } + } + + const stakingStatus = getEarningStatusByNominations(allActiveStake, nominationList); + + return { + status: stakingStatus, + balanceToken: this.nativeToken.slug, + totalStake: allActiveStake.toString(), + activeStake: allActiveStake.toString(), + unstakeBalance: '0', + isBondedBefore: true, + nominations: nominationList, + unstakings: [] + } as unknown as YieldPositionInfo; + } + + async parseNominatorMetadata (chainInfo: _ChainInfo, delegatorState: TaoStakingStakeOption[]): Promise> { + const bnMinBond = await this.getMinBond(); + + return this.parseNominatorMetadataBase(chainInfo, delegatorState, bnMinBond.toString()); + } + + override async subscribePoolPosition (useAddresses: string[], rsCallback: (rs: YieldPositionInfo) => void): Promise { + let cancel = false; + const substrateApi = await this.substrateApi.isReady; + const defaultInfo = this.baseInfo; + const chainInfo = this.chainInfo; + const _delegateInfo = await this.bittensorCache.get(); + + const getPoolPosition = async () => { + const rawDelegateStateInfos = await Promise.all( + useAddresses.map(async (address) => (await substrateApi.api.call.stakeInfoRuntimeApi.getStakeInfoForColdkey(address)).toJSON()) + ); + + if (rawDelegateStateInfos && rawDelegateStateInfos.length > 0) { + rawDelegateStateInfos.forEach((rawDelegateStateInfo, i) => { + const owner = reformatAddress(useAddresses[i], 42); + const delegatorState: TaoStakingStakeOption[] = []; + let bnTotalBalance = BN_ZERO; + + const delegateStateInfo = rawDelegateStateInfo as unknown as TaoStakeInfo[]; + + const totalDelegate: Record = {}; + + for (const delegate of delegateStateInfo) { + const hotkey = delegate.hotkey; + const netuid = delegate.netuid; + const stake = new BigN(delegate.stake); + + if (netuid === 0) { + const taoStake = stake.toFixed(0); + + if (totalDelegate[hotkey]) { + totalDelegate[hotkey] = new BigN(totalDelegate[hotkey]).plus(taoStake).toFixed(); + } else { + totalDelegate[hotkey] = taoStake; + } + } + } + + for (const hotkey in totalDelegate) { + bnTotalBalance = bnTotalBalance.add(new BN(totalDelegate[hotkey])); + let identity = ''; + + if (_delegateInfo) { + const delegateInfo = _delegateInfo.data.find((info) => info.hotkey.ss58 === hotkey); + + identity = delegateInfo ? delegateInfo.name : ''; + } + + delegatorState.push({ + owner: hotkey, + amount: totalDelegate[hotkey], + identity: identity + }); + } + + if (delegateStateInfo && delegateStateInfo.length > 0) { + this.parseNominatorMetadata(chainInfo, delegatorState) + .then((nominatorMetadata) => { + rsCallback({ + ...defaultInfo, + ...nominatorMetadata, + address: owner, + type: this.type + }); + }) + .catch((error) => taoStakingLogger.error('Error fetching nominator metadata', error)); + } else { + rsCallback({ + ...defaultInfo, + type: this.type, + address: owner, + balanceToken: this.nativeToken.slug, + totalStake: '0', + activeStake: '0', + unstakeBalance: '0', + status: EarningStatus.NOT_STAKING, + isBondedBefore: false, + nominations: [], + unstakings: [] + }); + } + }); + } + }; + + const getStakingPositionInterval = async () => { + if (cancel) { + return; + } + + await getPoolPosition(); + }; + + getStakingPositionInterval().catch((error) => taoStakingLogger.error('Error in getStakingPositionInterval', error)); + + const intervalId = setInterval(() => { + getStakingPositionInterval().catch((error) => taoStakingLogger.error('Error in getStakingPositionInterval', error)); + }, BITTENSOR_REFRESH_STAKE_INFO); + + return () => { + cancel = true; + clearInterval(intervalId); + }; + } + + // Because not have subscan api + override async checkAccountHaveStake (useAddresses: string[]): Promise { + return Promise.resolve([]); + } + + /* Subscribe pool position */ + + /* Get pool targets */ + // eslint-disable-next-line @typescript-eslint/require-await + private async getDevnetPoolTargets (netuid?: number): Promise { + const testnetDelegate = (await this.substrateApi.api.call.delegateInfoRuntimeApi.getDelegates()).toJSON() as unknown as TestnetBittensorDelegateInfo[]; + const bnMinBond = await this.getMinBond(netuid); + + const filteredDelegates = testnetDelegate.filter((delegate) => { + return delegate.returnPer1000 !== 0; + }); + + return filteredDelegates.map((delegate) => ({ + address: delegate.delegateSs58, + totalStake: '0', + ownStake: '0', + otherStake: '0', + minBond: bnMinBond.toString(), + nominatorCount: delegate.nominators.length, + commission: delegate.take / 1000, + blocked: false, + isVerified: false, + chain: this.chain, + isCrowded: false + }) as unknown as ValidatorInfo); + } + + private async getMainnetPoolTargets (netuid: number): Promise { + const _topValidator = await this.bittensorCache.get(); + + const topValidator = _topValidator; + const bnMinBond = await this.getMinBond(); + const validatorList = topValidator.data; + + const aprResponse = await this.bittensorCache.fetchApr(netuid); + const aprMap: Record = {}; + + aprResponse.data.forEach((item) => { + aprMap[item.hotkey.ss58] = item.thirty_day_apy; + }); + + const results = await Promise.all( + validatorList.map((validator) => { + const address = validator.hotkey.ss58; + // With bittensor we use total weight, root weight and alpha staked insted of total stake, own stake and other stake + const bnTotalWeightStake = new BigN(validator.global_weighted_stake); + const bnRootWeightStake = new BigN(validator.weighted_root_stake); + const bnAlphaStake = new BigN(validator.global_alpha_stake_as_tao); + + const nominatorCount = validator.global_nominators; + const commission = validator.take; + const roundedCommission = (parseFloat(commission) * 100).toFixed(0); + + const apr = aprMap[address]; + const expectedReturn = apr ? new BigN(apr).multipliedBy(100).toFixed(2) : '0'; + + const name = validator.name || address; + + return { + address: address, + totalStake: bnTotalWeightStake.toString(), + ownStake: bnRootWeightStake.toString(), + otherStake: bnAlphaStake.toString(), + minBond: bnMinBond.toString(), + nominatorCount: nominatorCount, + commission: roundedCommission, + expectedReturn: expectedReturn, + blocked: false, + isVerified: false, + chain: this.chain, + isCrowded: false, + identity: name + } as unknown as ValidatorInfo; + }) + ); + + return results; + } + + async getPoolTargets (netuid?: number): Promise { + if (this.chain === 'bittensor') { + return this.getMainnetPoolTargets(netuid ?? 0); + } else { + return this.getDevnetPoolTargets(netuid); + } + } + + /* Get pool targets */ + + /* Join pool action */ + + override async createJoinExtrinsic ( + data: SubmitJoinNativeStaking, + positionInfo?: YieldPositionInfo, + bondDest = 'Staked' + ): Promise<[TransactionData, YieldTokenBaseInfo]> { + const { amount, selectedValidators: targetValidators, subnetData } = data; + + const chainApi = await this.substrateApi.isReady; + const binaryAmount = new BigN(amount); + const selectedValidatorInfo = targetValidators[0]; + const hotkey = selectedValidatorInfo.address; + + const netuid = subnetData?.netuid ?? 0; + const slippage = subnetData?.slippage ?? DEFAULT_BITTENSOR_SLIPPAGE; + + const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid)); + const limitPrice = alphaToTaoPrice + .multipliedBy(10 ** _getAssetDecimals(this.nativeToken)) + .multipliedBy(1 + slippage); + + const BNlimitPrice = new BigN(limitPrice.integerValue(BigN.ROUND_CEIL).toFixed()); + + const extrinsic = chainApi.api.tx.subtensorModule.addStakeLimit( + hotkey, + netuid, + binaryAmount.toFixed(), + BNlimitPrice.toFixed(), + false + ); + + return [extrinsic, { slug: this.nativeToken.slug, amount: '0' }]; + } + + // Validate for case stake more + public override async validateYieldJoin (data: SubmitJoinNativeStaking, path: OptimalYieldPath): Promise { + const baseErrors = await super.validateYieldJoin(data, path); + + if (baseErrors.length > 0) { + return baseErrors; + } + + const { amount, subnetData } = data; + + const bnMinStake = await this.getMinBond(subnetData?.netuid); + + if (new BigN(amount).lt(bnMinStake)) { + return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.insufficientStakeToEarn', { replace: { bnMinStake: formatNumber(bnMinStake, _getAssetDecimals(this.nativeToken)), symbol: _getAssetSymbol(this.nativeToken) } }))]; + } + + return baseErrors; + } + + /* Join pool action */ + + /* Leave pool action */ + + override async handleYieldUnstake (amount: string, address: string, selectedTarget?: string, netuid = 0, slippage: number = DEFAULT_BITTENSOR_SLIPPAGE): Promise<[ExtrinsicType, TransactionData]> { + const apiPromise = await this.substrateApi.isReady; + + if (!selectedTarget) { + return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS)); + } + + const binaryAmount = new BigN(amount); + + const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid)); + const limitPrice = alphaToTaoPrice + .multipliedBy(10 ** _getAssetDecimals(this.nativeToken)) + .multipliedBy(1 - slippage); + + const BNlimitPrice = new BigN(limitPrice.integerValue(BigN.ROUND_CEIL).toFixed()); + + const extrinsic = apiPromise.api.tx.subtensorModule.removeStakeLimit( + selectedTarget, + netuid, + binaryAmount.toFixed(), + BNlimitPrice.toFixed(), + false + ); + + return [ExtrinsicType.STAKING_UNBOND, extrinsic]; + } + + public override async validateYieldLeave (amount: string, address: string, fastLeave: boolean, selectedTarget?: string, slug?: string, poolInfo?: YieldPoolInfo): Promise { + const baseErrors = await super.validateYieldLeave(amount, address, fastLeave, selectedTarget, slug); + + if (baseErrors.length > 0) { + return baseErrors; + } + + if (!poolInfo) { + return [new TransactionError(BasicTxErrorType.INVALID_PARAMS)]; + } + + const netuid = poolInfo.metadata.subnetData?.netuid; + const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid || 0)); + + const minDelegatorStake = await this.getMinBond(netuid); + + const minUnstake = minDelegatorStake.dividedBy(alphaToTaoPrice); + + if (new BigN(amount).lt(minUnstake)) { + return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.unstakeAmountTooLow', { replace: { bnMinUnstake: formatNumber(minUnstake, _getAssetDecimals(this.nativeToken)), symbol: poolInfo.metadata.subnetData?.subnetSymbol || _getAssetSymbol(this.nativeToken) } }))]; + } + + return baseErrors; + } + + /* Leave pool action */ + + /* Change validator */ + override async handleChangeEarningValidator (data: SubmitBittensorChangeValidatorStaking): Promise { + const chainApi = await this.substrateApi.isReady; + const { amount, maxAmount, metadata, originValidator, selectedValidators: targetValidators, subnetData } = data; + + if (!originValidator) { + return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS)); + } + + const netuid = subnetData?.netuid || 0; + const selectedValidatorInfo = targetValidators[0]; + const destValidator = selectedValidatorInfo.address; + + if (new BigN(amount).lte(0)) { + return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.amountMustBeGreaterThanZero'))); + } + + if (originValidator === destValidator) { + return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.fromValidatorSameAsTo'))); + } + + const alphaToTaoPrice = new BigN(await getAlphaToTaoRate(this.substrateApi, netuid)); + const bnMinStake = await this.getMinBond(netuid); + const minUnstake = bnMinStake.dividedBy(alphaToTaoPrice); + + const formattedMinUnstake = minUnstake.dividedBy(1000000).integerValue(BigN.ROUND_CEIL).dividedBy(1000); + + const bnMinMoveStake = formattedMinUnstake.multipliedBy(10 ** _getAssetDecimals(this.nativeToken)); + + if (new BigN(amount).lt(bnMinMoveStake)) { + return Promise.reject(new TransactionError(BasicTxErrorType.INVALID_PARAMS, t('bg.EARNING.services.service.earning.nativeStaking.tao.moveStakeAmountTooLow', { replace: { bnMinMoveStake: formattedMinUnstake.toString(), symbol: metadata?.subnetSymbol || '' } }))); + } + + // Avoid remaining amount too low -> can't do anything with that amount + if (!(maxAmount === amount) && new BigN(maxAmount).minus(new BigN(amount)).lt(bnMinMoveStake)) { + return Promise.reject(new TransactionError(StakingTxErrorType.REMAINING_AMOUNT_TOO_LOW, + t('bg.EARNING.services.service.earning.nativeStaking.tao.remainingStakeBelowMinimumWarning', { replace: { maxAmount: formatNumber(maxAmount, _getAssetDecimals(this.nativeToken)), subnetSymbol: metadata?.subnetSymbol || _getAssetSymbol(this.nativeToken) } }))); + } + + const extrinsic = chainApi.api.tx.subtensorModule.moveStake(originValidator, destValidator, netuid, netuid, amount); + + return extrinsic; + } +} diff --git a/packages/extension-base/src/services/earning-service/handlers/special.ts b/packages/extension-base/src/services/earning-service/handlers/special.ts index 37b15d8da45..11f82c88a4c 100644 --- a/packages/extension-base/src/services/earning-service/handlers/special.ts +++ b/packages/extension-base/src/services/earning-service/handlers/special.ts @@ -9,6 +9,7 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State' import { createXcmExtrinsicV2 } from '@subwallet/extension-base/services/balance-service/transfer/xcm'; import { estimateXcmFee } from '@subwallet/extension-base/services/balance-service/transfer/xcm/utils'; import { _getAssetDecimals, _getAssetExistentialDeposit, _getAssetName, _getAssetSymbol, _getChainNativeTokenSlug, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BaseYieldStepDetail, BasicTxErrorType, HandleYieldStepData, OptimalYieldPath, OptimalYieldPathParams, RequestCrossChainTransfer, RequestEarlyValidateYield, ResponseEarlyValidateYield, SpecialYieldPoolInfo, SpecialYieldPoolMetadata, SubmitChangeValidatorStaking, SubmitYieldJoinData, SubmitYieldStepData, TransactionData, UnstakingInfo, YieldPoolInfo, YieldPoolTarget, YieldPoolType, YieldProcessValidation, YieldStepBaseInfo, YieldStepType, YieldTokenBaseInfo, YieldValidationStatus } from '@subwallet/extension-base/types'; import { createPromiseHandler, formatNumber, PromiseHandler } from '@subwallet/extension-base/utils'; import { getId } from '@subwallet/extension-base/utils/getId'; @@ -19,6 +20,8 @@ import { BN, BN_TEN, BN_ZERO, noop } from '@polkadot/util'; import BasePoolHandler from './base'; +const specialEarningLogger = createLogger('SpecialEarning'); + export default abstract class BaseSpecialStakingPoolHandler extends BasePoolHandler { protected abstract altInputAsset: string; protected abstract derivativeAssets: string[]; @@ -194,7 +197,7 @@ export default abstract class BaseSpecialStakingPoolHandler extends BasePoolHand const getStatInterval = () => { if (!this.isActive) { - defaultCallback().catch(console.error); + defaultCallback().catch((error) => specialEarningLogger.error('Error in default callback', error)); } else { defaultCallback() .then(() => { @@ -203,7 +206,7 @@ export default abstract class BaseSpecialStakingPoolHandler extends BasePoolHand .then((rs) => { _callback(rs); }) - .catch(console.error); + .catch((error) => specialEarningLogger.error('Error in special earning handler', error)); } }; diff --git a/packages/extension-base/src/services/earning-service/service.ts b/packages/extension-base/src/services/earning-service/service.ts index b75e6f9cab1..b73d9a044c3 100644 --- a/packages/extension-base/src/services/earning-service/service.ts +++ b/packages/extension-base/src/services/earning-service/service.ts @@ -15,9 +15,12 @@ import DatabaseService from '@subwallet/extension-base/services/storage-service/ import { SWTransactionBase } from '@subwallet/extension-base/services/transaction-service/types'; import { BasicTxErrorType, EarningRewardHistoryItem, EarningRewardItem, EarningRewardJson, HandleYieldStepData, HandleYieldStepParams, OptimalYieldPath, OptimalYieldPathParams, RequestEarlyValidateYield, RequestEarningImpact, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestYieldLeave, RequestYieldWithdrawal, ResponseEarlyValidateYield, SubmitChangeValidatorStaking, TransactionData, ValidateYieldProcessParams, ValidatorInfo, YieldPoolInfo, YieldPoolTarget, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types'; import { addLazy, createPromiseHandler, filterAddressByChainInfo, PromiseHandler, removeLazy } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { fetchStaticCache } from '@subwallet/extension-base/utils/fetchStaticCache'; import { BehaviorSubject, combineLatest } from 'rxjs'; +const earningServiceLogger = createLogger('EarningService'); + import { EarningImpactResult } from './handlers/native-staking/dtao'; import TanssiNativeStakingPoolHandler from './handlers/native-staking/tanssi'; import { AcalaLiquidStakingPoolHandler, AmplitudeNativeStakingPoolHandler, AstarNativeStakingPoolHandler, BasePoolHandler, BifrostLiquidStakingPoolHandler, BifrostMantaLiquidStakingPoolHandler, EnergyNativeStakingPoolHandler, InterlayLendingPoolHandler, NominationPoolHandler, ParallelLiquidStakingPoolHandler, ParaNativeStakingPoolHandler, RelayNativeStakingPoolHandler, StellaSwapLiquidStakingPoolHandler, SubnetTaoStakingPoolHandler, TaoNativeStakingPoolHandler } from './handlers'; @@ -296,7 +299,7 @@ export default class EarningService implements StoppableServiceInterface, Persis if (eventTypes.includes('account.updateCurrent') || eventTypes.includes('account.remove') || eventTypes.includes('chain.updateState') || delayReload) { if (delayReload) { this.delayReloadTimeout = setTimeout(() => { - this.reloadEarning().catch(console.error); // Timeout is removed inside reloadEarning > runUnsubscribePoolsPosition + this.reloadEarning().catch((error) => earningServiceLogger.error('Error reloading earning', error)); // Timeout is removed inside reloadEarning > runUnsubscribePoolsPosition }, 3000); } else { this.delayReloadTimeout && clearTimeout(this.delayReloadTimeout); @@ -304,7 +307,7 @@ export default class EarningService implements StoppableServiceInterface, Persis await this.reloadEarning(); } } - })().catch(console.error); + })().catch((error) => earningServiceLogger.error('Error in earning service operation', error)); }); } @@ -343,7 +346,7 @@ export default class EarningService implements StoppableServiceInterface, Persis // cache identities of validators in native staking if (this.useOnlineCacheOnly && !this.validatorInfoCachingInterval) { - this.runIntervalGetPoolTargets().catch(console.error); + this.runIntervalGetPoolTargets().catch((error) => earningServiceLogger.error('Error running interval get pool targets', error)); } // Update promise handler @@ -464,7 +467,7 @@ export default class EarningService implements StoppableServiceInterface, Persis unsub(); } }) - .catch(console.error); + .catch((error) => earningServiceLogger.error('Error in earning service', error)); } } @@ -524,7 +527,7 @@ export default class EarningService implements StoppableServiceInterface, Persis this.yieldPoolInfoSubject.next(yieldPoolInfo); // Persist data - this.dbService.updateYieldPoolsStore(queue).catch(console.warn); + this.dbService.updateYieldPoolsStore(queue).catch((error) => earningServiceLogger.warn('Error updating yield pools store', error)); }, 300, 900); } @@ -564,7 +567,7 @@ export default class EarningService implements StoppableServiceInterface, Persis const onlineData = await this.fetchingPoolsInfoOnline(); const interval = setInterval(() => { - this.fetchingPoolsInfoOnline().catch(console.error); + this.fetchingPoolsInfoOnline().catch((error) => earningServiceLogger.error('Error fetching pools info online', error)); }, CRON_REFRESH_CHAIN_STAKING_METADATA); // Fetching from chains @@ -576,7 +579,7 @@ export default class EarningService implements StoppableServiceInterface, Persis rs(); clearInterval(interval); }; - }).catch(console.error); + }).catch((error) => earningServiceLogger.error('Error in earning service operation', error)); } runUnsubscribePoolsInfo () { @@ -612,7 +615,7 @@ export default class EarningService implements StoppableServiceInterface, Persis unsubList.push(unsub); } }) - .catch(console.error); + .catch((error) => earningServiceLogger.error('Error in earning service', error)); } } @@ -709,7 +712,7 @@ export default class EarningService implements StoppableServiceInterface, Persis this.yieldPositionSubject.next(yieldPositionInfo); // Persist data - this.dbService.updateYieldPositions(queue).catch(console.warn); + this.dbService.updateYieldPositions(queue).catch((error) => earningServiceLogger.warn('Error updating yield positions', error)); }, 300, 900); } @@ -738,7 +741,7 @@ export default class EarningService implements StoppableServiceInterface, Persis this.updateYieldPosition(data); }).then((rs) => { this.yieldPositionUnsub = rs; - }).catch(console.error); + }).catch((error) => earningServiceLogger.error('Error in earning service operation', error)); } runUnsubscribePoolsPosition () { @@ -796,7 +799,7 @@ export default class EarningService implements StoppableServiceInterface, Persis unsubList.push(unsub); } }) - .catch(console.error); + .catch((error) => earningServiceLogger.error('Error in earning service', error)); } } @@ -832,12 +835,12 @@ export default class EarningService implements StoppableServiceInterface, Persis this.getPoolReward(addresses, (result: EarningRewardItem) => { this.updateEarningReward(result); - }).catch(console.error); + }).catch((error) => earningServiceLogger.error('Error in earning service operation', error)); this.earningsRewardInterval = setInterval(() => { this.getPoolReward(addresses, (result: EarningRewardItem) => { this.updateEarningReward(result); - }).catch(console.error); + }).catch((error) => earningServiceLogger.error('Error in earning service operation', error)); }, CRON_REFRESH_STAKING_REWARD_FAST_INTERVAL); } @@ -866,7 +869,7 @@ export default class EarningService implements StoppableServiceInterface, Persis unsubList.push(unsub); } }) - .catch(console.error); + .catch((error) => earningServiceLogger.error('Error in earning service', error)); } } @@ -942,7 +945,7 @@ export default class EarningService implements StoppableServiceInterface, Persis unsub = _unsub; } }) - .catch(console.error); + .catch((error) => earningServiceLogger.error('Error fetching earning reward history', error)); }; if (!cancel) { @@ -1009,7 +1012,7 @@ export default class EarningService implements StoppableServiceInterface, Persis return { ...newData }; } } catch (e) { - console.error(e); + earningServiceLogger.error('Error in earning service', e); } const prevValueCached = this.poolTargetsFetchingCached.getValue(); @@ -1024,7 +1027,7 @@ export default class EarningService implements StoppableServiceInterface, Persis try { poolInfosSubjectValue = await fetchPoolsData(); } catch (e) { - console.log('Error fetching pools data:', e); + earningServiceLogger.error('Error fetching pools data', e); } } @@ -1050,7 +1053,7 @@ export default class EarningService implements StoppableServiceInterface, Persis }); this.poolTargetsFetchingCached.next(poolTargetsFetchingCached); - }).catch(console.error); + }).catch((error) => earningServiceLogger.error('Error in earning service operation', error)); }; updatePoolTarget(); diff --git a/packages/extension-base/src/services/event-service/index.ts b/packages/extension-base/src/services/event-service/index.ts index a974b9b6b8c..641e31d4d62 100644 --- a/packages/extension-base/src/services/event-service/index.ts +++ b/packages/extension-base/src/services/event-service/index.ts @@ -2,10 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 // Stateless service handle runtime event on background +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { EventItem, EventRegistry, EventType } from '@subwallet/extension-base/services/event-service/types'; import { TARGET_ENV } from '@subwallet/extension-base/utils'; import EventEmitter from 'eventemitter3'; +const eventServiceLogger = createLogger('EventService'); + const DEFAULT_LAZY_TIME = 300; const LONG_LAZY_TIME = 900; const LONG_LAZY_EVENTS: EventType[] = [ @@ -94,7 +97,7 @@ export class EventService extends EventEmitter { try { this.lazyEmitter.emit('lazy', this.pendingEvents, this.pendingEvents.map((e) => e.type)); } catch (e) { - console.error('Get error in some listener of lazy event', e); + eventServiceLogger.error('Get error in some listener of lazy event', e); } this.pendingEvents = []; @@ -114,7 +117,7 @@ export class EventService extends EventEmitter { } public override emit (eventType: T, ...args: EventEmitter.EventArgs): boolean { - console.debug('Emit event: ', eventType, ...args); + eventServiceLogger.debug('Emit event', eventType, ...args); this.pendingEvents.push({ type: eventType, data: args as EventRegistry[T] }); this.setLazyTimeout(eventType); diff --git a/packages/extension-base/src/services/fee-service/service.ts b/packages/extension-base/src/services/fee-service/service.ts index 6ac6609ce85..c2bf530d132 100644 --- a/packages/extension-base/src/services/fee-service/service.ts +++ b/packages/extension-base/src/services/fee-service/service.ts @@ -4,9 +4,12 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils'; import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { EvmFeeInfo, FeeChainType, FeeInfo, FeeSubscription } from '@subwallet/extension-base/types'; import { BehaviorSubject } from 'rxjs'; +const feeServiceLogger = createLogger('FeeService'); + export default class FeeService { protected readonly state: KoniState; @@ -143,7 +146,7 @@ export default class FeeService { observer.next(info); }) .catch((e) => { - console.warn(`Cannot get fee param for ${chain}`, e); + feeServiceLogger.warn(`Cannot get fee param for ${chain}`, e); observer.next({ type: 'evm', gasPrice: '0', @@ -152,7 +155,7 @@ export default class FeeService { } as EvmFeeInfo); }); } else { - console.warn(`Cannot get fee param for ${chain}`, 'Cannot get api'); + feeServiceLogger.warn(`Cannot get fee param for ${chain}`, 'Cannot get api'); observer.next({ type: 'evm', @@ -168,7 +171,7 @@ export default class FeeService { .then((info) => { observer.next(info); }) - .catch(console.error); + .catch((error) => feeServiceLogger.error('Error in fee service operation', error)); } else { observer.next({ type, diff --git a/packages/extension-base/src/services/fee-service/utils/index.ts b/packages/extension-base/src/services/fee-service/utils/index.ts index 22f71cb65d0..8280bd0ff51 100644 --- a/packages/extension-base/src/services/fee-service/utils/index.ts +++ b/packages/extension-base/src/services/fee-service/utils/index.ts @@ -5,6 +5,7 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { GAS_PRICE_RATIO, NETWORK_MULTI_GAS_FEE } from '@subwallet/extension-base/constants'; import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; import { estimateTokensForPool, getReserveForPool } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { EvmEIP1559FeeOption, EvmFeeInfo, EvmFeeInfoCache, InfuraFeeInfo, InfuraThresholdInfo } from '@subwallet/extension-base/types'; import { BN_WEI, BN_ZERO } from '@subwallet/extension-base/utils'; import BigN from 'bignumber.js'; @@ -13,6 +14,8 @@ import { ApiPromise } from '@polkadot/api'; import { gasStation, POLYGON_GAS_INDEXER } from '../../balance-service/transfer/xcm/polygonBridge'; +const feeServiceUtilsLogger = createLogger('FeeServiceUtils'); + const INFURA_API_KEY = process.env.INFURA_API_KEY || ''; const INFURA_API_KEY_SECRET = process.env.INFURA_API_KEY_SECRET || ''; const INFURA_AUTH = 'Basic ' + Buffer.from(INFURA_API_KEY + ':' + INFURA_API_KEY_SECRET).toString('base64'); @@ -79,7 +82,7 @@ export const fetchInfuraFeeData = async (chainId: number, infuraAuth?: string): return parseInfuraFee(feeInfo, thresholdInfo); } catch (e) { - console.warn(e); + feeServiceUtilsLogger.warn('Error in fee service utils', e); return null; } @@ -102,7 +105,7 @@ export const fetchSubWalletFeeData = async (chainId: number, networkKey: string) resolve(info); }) .catch((e) => { - console.warn(e); + feeServiceUtilsLogger.warn('Error in fee service utils', e); resolve(null); }); }); @@ -117,7 +120,7 @@ export const fetchOnlineFeeData = async (chainId: number, networkKey: string, us resolve(info); }) .catch((e) => { - console.warn(e); + feeServiceUtilsLogger.warn('Error in fee service utils', e); resolve(null); }); }); diff --git a/packages/extension-base/src/services/fee-service/utils/tokenPayFee.ts b/packages/extension-base/src/services/fee-service/utils/tokenPayFee.ts index 79e5058ea82..6738e36aab4 100644 --- a/packages/extension-base/src/services/fee-service/utils/tokenPayFee.ts +++ b/packages/extension-base/src/services/fee-service/utils/tokenPayFee.ts @@ -6,11 +6,14 @@ import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/ import { _getAssetDecimals, _getAssetPriceId, _getTokenOnChainAssetId } from '@subwallet/extension-base/services/chain-service/utils'; import { RequestAssetHubTokensCanPayFee, RequestHydrationTokensCanPayFee, TokenHasBalanceInfo } from '@subwallet/extension-base/services/fee-service/interfaces'; import { checkLiquidityForPool, estimateTokensForPool, getReserveForPool } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk'; import BigN from 'bignumber.js'; import { SubmittableExtrinsic } from '@polkadot/api/promise/types'; +const tokenPayFeeLogger = createLogger('TokenPayFee'); + export async function getAssetHubTokensCanPayFee (request: RequestAssetHubTokensCanPayFee): Promise { const { chainService, feeAmount, nativeBalanceInfo, nativeTokenInfo, substrateApi, tokensHasBalanceInfoMap } = request; const tokensList: TokenHasBalanceInfo[] = [nativeBalanceInfo]; @@ -26,7 +29,7 @@ export async function getAssetHubTokensCanPayFee (request: RequestAssetHubTokens const token = chainService.getAssetBySlug(tokenSlug); if (!token) { - console.error(`[getAssetHubTokensCanPayFee] Token not found for slug: ${tokenSlug}`); + tokenPayFeeLogger.error(`[getAssetHubTokensCanPayFee] Token not found for slug: ${tokenSlug}`); } return token; @@ -71,7 +74,7 @@ export async function getAssetHubTokensCanPayFee (request: RequestAssetHubTokens } } } catch (e) { - console.error('error when fetching pool with token', tokenInfo.slug, e); + tokenPayFeeLogger.error('error when fetching pool with token', tokenInfo.slug, e); } })); @@ -100,7 +103,7 @@ export async function getHydrationTokensCanPayFee (request: RequestHydrationToke const token = chainService.getAssetBySlug(tokenSlug); if (!token) { - console.error(`[getHydrationTokensCanPayFee] Token not found for slug: ${tokenSlug}`); + tokenPayFeeLogger.error(`[getHydrationTokensCanPayFee] Token not found for slug: ${tokenSlug}`); } return token; @@ -201,7 +204,7 @@ export async function getHydrationRate (address: string, hdx: _ChainAsset, desTo quoteRate = quote.rate; } catch (error) { - console.error(`Failed to fetch swap quote: ${(error as Error).message}`); + tokenPayFeeLogger.error(`Failed to fetch swap quote: ${(error as Error).message}`); } if (quoteRate) { diff --git a/packages/extension-base/src/services/hiro-service/utils/index.ts b/packages/extension-base/src/services/hiro-service/utils/index.ts index 082218c411a..062125e3981 100644 --- a/packages/extension-base/src/services/hiro-service/utils/index.ts +++ b/packages/extension-base/src/services/hiro-service/utils/index.ts @@ -2,8 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 import { Brc20Metadata, InscriptionFetchedData } from '@subwallet/extension-base/services/chain-service/handler/bitcoin/strategy/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { HiroService } from '@subwallet/extension-base/services/hiro-service'; +const hiroServiceLogger = createLogger('HiroService'); + // todo: handle inscription testnet export async function getBrc20Metadata (isTestnet = false, ticker: string) { const hiroService = HiroService.getInstance(isTestnet); @@ -25,7 +28,7 @@ export async function getBrc20Metadata (isTestnet = false, ticker: string) { return defaultMetadata; } catch (error) { - console.log(`Error on request brc20 metadata with ticker ${ticker}`); + hiroServiceLogger.debug(`Error on request brc20 metadata with ticker ${ticker}`); return defaultMetadata; } @@ -37,7 +40,7 @@ export async function getInscriptionContent (isTestnet: boolean, inscriptionId: try { return await hiroService.getInscriptionContent(inscriptionId); } catch (error) { - console.log(`Error on request inscription ${inscriptionId} content`); + hiroServiceLogger.debug(`Error on request inscription ${inscriptionId} content`); return {}; } @@ -56,7 +59,7 @@ export async function getAddressInscriptions (address: string, isTestnet: boolea return response.results; } catch (error) { - console.error(`Failed to get ${address} inscriptions with offset ${offset} and limit ${limit}`, error); + hiroServiceLogger.error(`Failed to get ${address} inscriptions with offset ${offset} and limit ${limit}`, error); throw error; } } @@ -67,7 +70,7 @@ export function getPreviewUrl (inscriptionId: string) { try { return hiroService.getPreviewUrl(inscriptionId); } catch (error) { - console.error(`Failed to get inscription ${inscriptionId} preview url`, error); + hiroServiceLogger.error(`Failed to get inscription ${inscriptionId} preview url`, error); throw error; } } diff --git a/packages/extension-base/src/services/history-service/helpers/recoverHistoryStatus.ts b/packages/extension-base/src/services/history-service/helpers/recoverHistoryStatus.ts index d94900db829..895adba8bb6 100644 --- a/packages/extension-base/src/services/history-service/helpers/recoverHistoryStatus.ts +++ b/packages/extension-base/src/services/history-service/helpers/recoverHistoryStatus.ts @@ -4,12 +4,15 @@ import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes'; import { ChainService } from '@subwallet/extension-base/services/chain-service'; import { _EvmApi } from '@subwallet/extension-base/services/chain-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isSameAddress } from '@subwallet/extension-base/utils'; import { Vec } from '@polkadot/types'; import { EventRecord } from '@polkadot/types/interfaces'; import { isHex } from '@polkadot/util'; +const recoverHistoryStatusLogger = createLogger('RecoverHistoryStatus'); + export enum HistoryRecoverStatus { SUCCESS = 'SUCCESS', FAILED = 'FAILED', @@ -45,7 +48,7 @@ const substrateRecover = async (history: TransactionHistoryItem, chainService: C if (!blockHash) { if (nonce === undefined || startBlock === undefined) { - console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`); + recoverHistoryStatusLogger.debug(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`); return { status: HistoryRecoverStatus.LACK_INFO }; } @@ -103,7 +106,7 @@ const substrateRecover = async (history: TransactionHistoryItem, chainService: C } if (index === undefined) { - console.log(`Fail to find extrinsic ${extrinsicHash} on ${chain}`); + recoverHistoryStatusLogger.debug(`Fail to find extrinsic ${extrinsicHash} on ${chain}`); return { status: HistoryRecoverStatus.FAIL_DETECT }; } @@ -125,12 +128,12 @@ const substrateRecover = async (history: TransactionHistoryItem, chainService: C return { status: HistoryRecoverStatus.FAIL_DETECT }; } else { - console.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`); + recoverHistoryStatusLogger.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`); return { status: HistoryRecoverStatus.API_INACTIVE }; } } catch (e) { - console.error(`Fail to update history ${chain}-${extrinsicHash}:`, (e as Error).message); + recoverHistoryStatusLogger.error(`Fail to update history ${chain}-${extrinsicHash}:`, (e as Error).message); return { status: HistoryRecoverStatus.UNKNOWN }; } @@ -174,7 +177,7 @@ const evmRecover = async (history: TransactionHistoryItem, chainService: ChainSe return { ...result, status: transactionReceipt.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED }; } else { if (nonce === undefined || startBlock === undefined) { - console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`); + recoverHistoryStatusLogger.debug(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`); return { ...result, status: HistoryRecoverStatus.LACK_INFO }; } @@ -204,12 +207,12 @@ const evmRecover = async (history: TransactionHistoryItem, chainService: ChainSe return { status: HistoryRecoverStatus.FAIL_DETECT }; } else { - console.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`); + recoverHistoryStatusLogger.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`); return { status: HistoryRecoverStatus.API_INACTIVE }; } } catch (e) { - console.error(`Fail to update history ${chain}-${extrinsicHash}:`, (e as Error).message); + recoverHistoryStatusLogger.error(`Fail to update history ${chain}-${extrinsicHash}:`, (e as Error).message); return { status: HistoryRecoverStatus.UNKNOWN }; } @@ -265,12 +268,12 @@ const bitcoinRecover = async (history: TransactionHistoryItem, chainService: Cha return { status: HistoryRecoverStatus.FAIL_DETECT }; } else { - console.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`); + recoverHistoryStatusLogger.error(`Fail to update history ${chain}-${extrinsicHash}: Api not active`); return { status: HistoryRecoverStatus.API_INACTIVE }; } } catch (e) { - console.error(`Fail to update history ${chain}-${extrinsicHash}:`, (e as Error).message); + recoverHistoryStatusLogger.error(`Fail to update history ${chain}-${extrinsicHash}:`, (e as Error).message); return { status: HistoryRecoverStatus.UNKNOWN }; } @@ -295,7 +298,7 @@ export const historyRecover = async (history: TransactionHistoryItem, chainServi const checkFunction = recoverFunctions[chainType]; if (!checkFunction) { - console.warn(`Chain type ${chainType} is not supported for recoverHistory`); + recoverHistoryStatusLogger.warn(`Chain type ${chainType} is not supported for recoverHistory`); return { status: HistoryRecoverStatus.UNKNOWN }; } @@ -303,7 +306,7 @@ export const historyRecover = async (history: TransactionHistoryItem, chainServi try { return await checkFunction(history, chainService); } catch (error) { - console.error(`Failed to recover history for chain type ${chainType}:`, error); + recoverHistoryStatusLogger.error(`Failed to recover history for chain type ${chainType}:`, error); return { status: HistoryRecoverStatus.FAILED }; } diff --git a/packages/extension-base/src/services/history-service/index.ts b/packages/extension-base/src/services/history-service/index.ts index e248b258f58..4bfd29517c5 100644 --- a/packages/extension-base/src/services/history-service/index.ts +++ b/packages/extension-base/src/services/history-service/index.ts @@ -15,10 +15,13 @@ import { KeyringService } from '@subwallet/extension-base/services/keyring-servi import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService'; import { SubscanService } from '@subwallet/extension-base/services/subscan-service'; import { getAddressesByChainType } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; import { keyring } from '@subwallet/ui-keyring'; import { BehaviorSubject } from 'rxjs'; +const historyServiceLogger = createLogger('HistoryService'); + function filterHistoryItemByAddressAndChain (chain: string, addresses: string[]) { return (item: TransactionHistoryItem) => { return item.chain === chain && addresses.includes(item.address); @@ -36,7 +39,7 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer private keyringService: KeyringService, private subscanService: SubscanService ) { - this.init().catch(console.error); + this.init().catch((error) => historyServiceLogger.error('Error initializing history service', error)); } private fetchPromise: Promise | null = null; @@ -123,7 +126,7 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer }); this.addHistoryItems(result).catch((e) => { - console.log('addHistoryItems in fetchAllPossibleExtrinsicItems error', e); + historyServiceLogger.error('addHistoryItems in fetchAllPossibleExtrinsicItems error', e); }); }).then((extrinsicItems) => { const excludeTransferExtrinsicHash: string[] = []; @@ -149,13 +152,13 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer }); this.addHistoryItems(result).catch((e) => { - console.log('addHistoryItems in fetchAllPossibleTransferItems-sent error', e); + historyServiceLogger.error('addHistoryItems in fetchAllPossibleTransferItems-sent error', e); }); }).catch((e) => { - console.log('fetchAllPossibleTransferItems-sent error', e); + historyServiceLogger.error('fetchAllPossibleTransferItems-sent error', e); }); }).catch((e) => { - console.log('fetchAllPossibleExtrinsicItems error', e); + historyServiceLogger.error('fetchAllPossibleExtrinsicItems error', e); }); this.subscanService.fetchAllPossibleTransferItems(groupId, chain, address, 'received').then((rsMap) => { @@ -173,10 +176,10 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer }); this.addHistoryItems(result).catch((e) => { - console.log('addHistoryItems in fetchAllPossibleTransferItems-receive error', e); + historyServiceLogger.error('addHistoryItems in fetchAllPossibleTransferItems-receive error', e); }); }).catch((e) => { - console.log('fetchAllPossibleTransferItems-receive error', e); + historyServiceLogger.error('fetchAllPossibleTransferItems-receive error', e); }); } @@ -232,7 +235,7 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer } } else if (_isChainBitcoinCompatible(chainInfo)) { this.fetchBitcoinTransactionHistory(chain, bitcoinAddresses).catch((e) => { - console.log('fetchBitcoinTransactionHistory Error', e); + historyServiceLogger.error('fetchBitcoinTransactionHistory Error', e); }); } @@ -306,7 +309,7 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer await this.recoverHistories(); this.recoverInterval = setInterval(() => { - this.recoverHistories().catch(console.error); + this.recoverHistories().catch((error) => historyServiceLogger.error('Error recovering histories', error)); }, CRON_RECOVER_HISTORY_INTERVAL); } @@ -352,11 +355,11 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer case HistoryRecoverStatus.FAILED: case HistoryRecoverStatus.SUCCESS: updateData.status = recoverResult.status === HistoryRecoverStatus.SUCCESS ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL; - this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch(console.error); + this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch((error) => historyServiceLogger.error('Error updating history by extrinsic hash', error)); delete this.#needRecoveryHistories[currentExtrinsicHash]; break; default: - this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch(console.error); + this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch((error) => historyServiceLogger.error('Error updating history by extrinsic hash', error)); delete this.#needRecoveryHistories[currentExtrinsicHash]; } }); @@ -371,16 +374,16 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer async init (): Promise { this.status = ServiceStatus.INITIALIZING; await this.eventService.waitCryptoReady; - this.restoreProcessTransaction().catch(console.error); + this.restoreProcessTransaction().catch((error) => historyServiceLogger.error('Error restoring process transaction', error)); await this.loadData(); Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => { - this.getHistories().catch(console.log); - this.recoverProcessingHistory().catch(console.error); + this.getHistories().catch((error) => historyServiceLogger.error('Error getting histories', error)); + this.recoverProcessingHistory().catch((error) => historyServiceLogger.error('Error recovering processing history', error)); this.eventService.on('account.remove', (address) => { - this.removeHistoryByAddress(address).catch(console.error); + this.removeHistoryByAddress(address).catch((error) => historyServiceLogger.error('Error removing history by address', error)); }); - }).catch(console.error); + }).catch((error) => historyServiceLogger.error('Error in history service operation', error)); this.status = ServiceStatus.INITIALIZED; } @@ -419,10 +422,10 @@ export class HistoryService implements StoppableServiceInterface, PersistDataSer const recoverNumber = Object.keys(this.#needRecoveryHistories).length; if (recoverNumber > 0) { - console.log(`Recover ${recoverNumber} processing history`); + historyServiceLogger.info(`Recover ${recoverNumber} processing history`); } - this.startRecoverHistories().catch(console.error); + this.startRecoverHistories().catch((error) => historyServiceLogger.error('Error starting recover histories', error)); } async start (): Promise { diff --git a/packages/extension-base/src/services/history-service/subscan-history.ts b/packages/extension-base/src/services/history-service/subscan-history.ts index 1b5e885d7d8..3f92749a106 100644 --- a/packages/extension-base/src/services/history-service/subscan-history.ts +++ b/packages/extension-base/src/services/history-service/subscan-history.ts @@ -6,8 +6,11 @@ import { ChainType, ExtrinsicStatus, ExtrinsicType, TransactionDirection, Transa import { _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils'; import { getExtrinsicParserKey, subscanExtrinsicParserMap, supportedExtrinsicParser } from '@subwallet/extension-base/services/history-service/helpers/subscan-extrinsic-parser-helper'; import { ExtrinsicItem, TransferItem } from '@subwallet/extension-base/services/subscan-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isSameAddress } from '@subwallet/extension-base/utils'; +const subscanHistoryLogger = createLogger('SubscanHistory'); + export function parseSubscanExtrinsicData (address: string, extrinsicItem: ExtrinsicItem, chainInfo: _ChainInfo): TransactionHistoryItem | null { const extrinsicParserKey = getExtrinsicParserKey(extrinsicItem); @@ -54,7 +57,7 @@ export function parseSubscanExtrinsicData (address: string, extrinsicItem: Extri try { return subscanExtrinsicParserMap[extrinsicParserKey](initData); } catch (e) { - console.log('parseSubscanExtrinsicData error:', e, initData); + subscanHistoryLogger.error('parseSubscanExtrinsicData error:', e, initData); return null; } diff --git a/packages/extension-base/src/services/history-service/subsquid-multi-chain-history.ts b/packages/extension-base/src/services/history-service/subsquid-multi-chain-history.ts index b2c6d994f1c..04a42d36aff 100644 --- a/packages/extension-base/src/services/history-service/subsquid-multi-chain-history.ts +++ b/packages/extension-base/src/services/history-service/subsquid-multi-chain-history.ts @@ -4,11 +4,14 @@ import { ApolloClient, createHttpLink, gql, InMemoryCache } from '@apollo/client'; import { _ChainInfo } from '@subwallet/chain-list/types'; import { ChainType, ExtrinsicStatus, ExtrinsicType, TransactionDirection, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { MAX_FETCH_PAGE_PER_SESSION, MIN__NUM_HISTORY_PER_ACCOUNT } from '@subwallet/extension-base/services/history-service/constants'; import { isArray } from '@polkadot/util'; import { decodeAddress, encodeAddress, isEthereumAddress } from '@polkadot/util-crypto'; +const subsquidMultiChainHistoryLogger = createLogger('SubsquidMultiChainHistory'); + const MULTI_CHAIN_URL = 'https://squid.subsquid.io/multi-chain-tx/v/v1/graphql'; const MultiChainTxClient = new ApolloClient({ @@ -394,7 +397,7 @@ export async function fetchMultiChainHistories (addresses: string[], chainMap: R const chainInfo = chainMap[chainId]; if (chainInfo === undefined) { - console.debug(`Not found chain info for chain id: ${chainId}`); // TODO: resolve conflicting chainId + subsquidMultiChainHistoryLogger.debug(`Not found chain info for chain id: ${chainId}`); // TODO: resolve conflicting chainId return; } @@ -411,7 +414,7 @@ export async function fetchMultiChainHistories (addresses: string[], chainMap: R histories.push(transactionData); } catch (e) { - console.debug('Parse transaction data failed', address, e); + subsquidMultiChainHistoryLogger.debug('Parse transaction data failed', address, e); } }); }); diff --git a/packages/extension-base/src/services/inapp-notification-service/index.ts b/packages/extension-base/src/services/inapp-notification-service/index.ts index a95833a2795..1dfcdfe1f5b 100644 --- a/packages/extension-base/src/services/inapp-notification-service/index.ts +++ b/packages/extension-base/src/services/inapp-notification-service/index.ts @@ -18,9 +18,12 @@ import DatabaseService from '@subwallet/extension-base/services/storage-service/ import { getTokenPairFromStep } from '@subwallet/extension-base/services/swap-service/utils'; import { ProcessTransactionData, ProcessType, SummaryEarningProcessData, SwapBaseTxData, YieldPoolType } from '@subwallet/extension-base/types'; import { GetNotificationParams, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { formatNumber, getAddressesByChainType, reformatAddress } from '@subwallet/extension-base/utils'; import { isSubstrateAddress } from '@subwallet/keyring'; +const inappNotificationServiceLogger = createLogger('InappNotificationService'); + export class InappNotificationService implements CronServiceInterface { status: ServiceStatus; private refeshAvailBridgeClaimTimeOut: NodeJS.Timeout | undefined; @@ -210,7 +213,7 @@ export class InappNotificationService implements CronServiceInterface { this.createAvailBridgeClaimNotification(); this.createPolygonClaimableTransactions().catch((err) => { - console.error('Error:', err); + inappNotificationServiceLogger.error('Error creating polygon claimable transactions', err); }); this.refeshAvailBridgeClaimTimeOut = setTimeout(this.cronCreateBridgeClaimNotification.bind(this), CRON_LISTEN_AVAIL_BRIDGE_CLAIM); @@ -261,21 +264,21 @@ export class InappNotificationService implements CronServiceInterface { substrateAddresses.forEach((address) => { fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.ETHEREUM, true) .then(async (transactions) => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.TEST_SUBSTRATE])) - .catch(console.error); + .catch((error) => inappNotificationServiceLogger.error('Error fetching Avail bridge claimable', error)); fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.ETHEREUM, false) .then(async (transactions) => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.MAIN_SUBSTRATE])) - .catch(console.error); + .catch((error) => inappNotificationServiceLogger.error('Error fetching Avail bridge claimable', error)); }); evmAddresses.forEach((address) => { fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.AVAIL, true) .then(async (transactions) => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.TEST_EVM])) - .catch(console.error); + .catch((error) => inappNotificationServiceLogger.error('Error fetching Avail bridge claimable', error)); fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.AVAIL, false) .then(async (transactions) => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.MAIN_EVM])) - .catch(console.error); + .catch((error) => inappNotificationServiceLogger.error('Error fetching Avail bridge claimable', error)); }); } @@ -494,7 +497,7 @@ export class InappNotificationService implements CronServiceInterface { async startCron (): Promise { this.cleanUpOldNotifications() - .catch(console.error); + .catch((error) => inappNotificationServiceLogger.error('Error cleaning up old notifications', error)); this.cronCreateBridgeClaimNotification(); return Promise.resolve(); @@ -521,7 +524,7 @@ export class InappNotificationService implements CronServiceInterface { } removeAccountNotifications (proxyId: string) { - this.dbService.removeAccountNotifications(proxyId).catch(console.error); + this.dbService.removeAccountNotifications(proxyId).catch((error) => inappNotificationServiceLogger.error('Error removing account notifications', error)); } migrateNotificationProxyId (proxyIds: string[], newProxyId: string, newName: string) { diff --git a/packages/extension-base/src/services/inapp-notification-service/utils/avail.ts b/packages/extension-base/src/services/inapp-notification-service/utils/avail.ts index 1c04b9a67ef..89ef5172774 100644 --- a/packages/extension-base/src/services/inapp-notification-service/utils/avail.ts +++ b/packages/extension-base/src/services/inapp-notification-service/utils/avail.ts @@ -1,8 +1,11 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BridgeTransactionStatus } from '../interfaces'; +const availBridgeUtilsLogger = createLogger('AvailBridgeUtils'); + /* Description */ export function getAvailBridgeClaimDescription (amount: string, symbol: string) { return `${amount} ${symbol} ready to claim from ${symbol} cross-chain transfer. Click to claim now!`; @@ -96,14 +99,14 @@ export async function fetchAvailBridgeTransactions (userAddress: string, sourceC ); if (!rawResponse.ok) { - console.error('Error fetching claimable bridge transactions'); + availBridgeUtilsLogger.error('Error fetching claimable bridge transactions'); return undefined; } return await rawResponse.json() as AvailBridgeTransactionsResponse; } catch (e) { - console.error(e); + availBridgeUtilsLogger.error('Error fetching Avail bridge transactions', e); return undefined; } diff --git a/packages/extension-base/src/services/inapp-notification-service/utils/polygon.ts b/packages/extension-base/src/services/inapp-notification-service/utils/polygon.ts index d904789d65a..1f0ebb579d5 100644 --- a/packages/extension-base/src/services/inapp-notification-service/utils/polygon.ts +++ b/packages/extension-base/src/services/inapp-notification-service/utils/polygon.ts @@ -1,8 +1,11 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BridgeTransactionStatus } from '../interfaces'; +const polygonBridgeUtilsLogger = createLogger('PolygonBridgeUtils'); + export const POLYGON_BRIDGE_INDEXER = { MAINNET: 'https://api-gateway.polygon.technology/api/v3/transactions/mainnet', TESTNET: 'https://api-gateway.polygon.technology/api/v3/transactions/testnet' @@ -111,14 +114,14 @@ export async function fetchPolygonBridgeTransactions (userAddress: string, isTes ); if (!rawResponse.ok) { - console.error('Error fetching claimable bridge transactions'); + polygonBridgeUtilsLogger.error('Error fetching claimable bridge transactions'); return undefined; } return await rawResponse.json() as PolygonTransactionResponse; } catch (e) { - console.error(e); + polygonBridgeUtilsLogger.error('Error fetching Polygon bridge transactions', e); return undefined; } diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts index 896cf58e574..c978edd9cca 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Derive.ts @@ -3,6 +3,7 @@ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { AccountJson, AccountProxyData, CommonAccountErrorType, CreateDeriveAccountInfo, DeriveAccountInfo, DeriveErrorType, NextDerivePair, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestGetDeriveAccounts, RequestGetDeriveSuggestion, ResponseDeriveValidateV2, ResponseGetDeriveAccounts, ResponseGetDeriveSuggestion, SWCommonAccountError, SWDeriveError } from '@subwallet/extension-base/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { createAccountProxyId, derivePair, findSoloNextDerive, findUnifiedNextDerive, getSoloDerivationInfo, parseUnifiedSuriToDerivationPath, validateDerivationPath } from '@subwallet/extension-base/utils'; import { BitcoinKeypairTypes, DefaultSubstrateKeypairTypes, EthereumKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; @@ -12,6 +13,9 @@ import { assert } from '@polkadot/util'; import { AccountBaseHandler } from './Base'; +const accountDeriveHandlerLogger = createLogger('AccountDeriveHandler'); + +const validDeriveKeypairTypes: KeypairType[] = [...SubstrateKeypairTypes, ...EthereumKeypairTypes, 'ton', 'cardano', ...BitcoinKeypairTypes]; const validDeriveKeypairTypes: KeypairType[] = [...DefaultSubstrateKeypairTypes, ...EthereumKeypairTypes, 'ton', 'cardano', ...BitcoinKeypairTypes]; /** @@ -81,7 +85,7 @@ export class AccountDeriveHandler extends AccountBaseHandler { this.state._addAddressToAuthList(address, isAllowed); result.push(childPair); } catch (e) { - console.log(e); + accountDeriveHandlerLogger.warn('Error creating derived account', e); } } diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts index 0336e234ea9..d4c50df2156 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Json.ts @@ -3,6 +3,7 @@ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { AccountProxyExtra, AccountProxyStoreData, AccountProxyType, KeyringPairs$JsonV2, ModifyPairStoreData, RequestAccountBatchExportV2, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestJsonGetAccountInfo, RequestJsonRestoreV2, ResponseAccountBatchExportV2, ResponseBatchJsonGetAccountInfo, ResponseJsonGetAccountInfo } from '@subwallet/extension-base/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { combineAccountsWithKeyPair, convertAccountProxyType, createPromiseHandler, transformAccount } from '@subwallet/extension-base/utils'; import { generateRandomString } from '@subwallet/extension-base/utils/getId'; import { createPair } from '@subwallet/keyring'; @@ -16,6 +17,8 @@ import { EncryptedJson, Prefix } from '@polkadot/util-crypto/types'; import { AccountBaseHandler } from './Base'; +const accountJsonHandlerLogger = createLogger('AccountJsonHandler'); + /** * @class AccountJsonHandler * @extends AccountBaseHandler @@ -48,7 +51,7 @@ export class AccountJsonHandler extends AccountBaseHandler { return true; } catch (e) { - console.error(e); + accountJsonHandlerLogger.error('Error validating password', e); return false; } @@ -86,7 +89,7 @@ export class AccountJsonHandler extends AccountBaseHandler { accountProxy: proxy }; } catch (e) { - console.error(e); + accountJsonHandlerLogger.error('Error parsing single JSON account info', e); throw new Error((e as Error).message); } } else { @@ -155,7 +158,7 @@ export class AccountJsonHandler extends AccountBaseHandler { try { rs.push(keyring.createFromJson(pair)); } catch (e) { - console.error(e); + accountJsonHandlerLogger.error('Error creating pair from JSON', e); } return rs; @@ -188,7 +191,7 @@ export class AccountJsonHandler extends AccountBaseHandler { accountProxies: result }; } catch (e) { - console.error(e); + accountJsonHandlerLogger.error('Error parsing multi JSON account info', e); throw new Error((e as Error).message); } } else { @@ -214,7 +217,7 @@ export class AccountJsonHandler extends AccountBaseHandler { rs.push(pair); } catch (e) { - console.error(e); + accountJsonHandlerLogger.error('Error creating pair from JSON', e); } return rs; @@ -318,7 +321,7 @@ export class AccountJsonHandler extends AccountBaseHandler { rs.push(address); } } catch (error) { - console.log(error); + accountJsonHandlerLogger.warn('Error getting pair during batch restore', error); } return rs; diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Migration.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Migration.ts index 29af68c18dd..de8ab8a3104 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Migration.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Migration.ts @@ -3,12 +3,15 @@ import { RequestMigrateSoloAccount, RequestMigrateUnifiedAndFetchEligibleSoloAccounts, RequestPingSession, ResponseMigrateSoloAccount, ResponseMigrateUnifiedAndFetchEligibleSoloAccounts, SoloAccountToBeMigrated } from '@subwallet/extension-base/background/KoniTypes'; import { AccountBaseHandler } from '@subwallet/extension-base/services/keyring-service/context/handlers/Base'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isTWAccount } from '@subwallet/extension-base/services/keyring-service/utils'; import { AccountChainType, AccountProxy, SUPPORTED_ACCOUNT_CHAIN_TYPES } from '@subwallet/extension-base/types'; import { createAccountProxyId, getDefaultKeypairTypeFromAccountChainType, getSuri } from '@subwallet/extension-base/utils'; import { generateRandomString } from '@subwallet/extension-base/utils/getId'; import { keyring } from '@subwallet/ui-keyring'; +const accountMigrationHandlerLogger = createLogger('AccountMigrationHandler'); + import { keyExtractSuri } from '@polkadot/util-crypto'; export const SESSION_TIMEOUT = 10000; @@ -134,7 +137,7 @@ export class AccountMigrationHandler extends AccountBaseHandler { unifiedAccountIds.push(unifiedAccount.id); } } catch (error) { - console.error('Migration unified account failed with error:', error); + accountMigrationHandlerLogger.error('Migration unified account failed with error', error); } finally { keyring.lockAll(false); this.parentService.updateKeyringState(); @@ -258,7 +261,7 @@ export class AccountMigrationHandler extends AccountBaseHandler { this.state.saveCurrentAccountProxyId(upcomingProxyId); } } catch (error) { - console.error('Migration solo account failed with error', error); + accountMigrationHandlerLogger.error('Migration solo account failed with error', error); } finally { keyring.lockAll(false); this.parentService.updateKeyringState(); diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts index 8332b0ba0c1..fa2f39ac87e 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Modify.ts @@ -4,6 +4,7 @@ import { RequestChangeMasterPassword, RequestMigratePassword, ResponseChangeMasterPassword, ResponseMigratePassword } from '@subwallet/extension-base/background/KoniTypes'; import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants'; import { AccountChainType, CommonAccountErrorType, RequestAccountProxyEdit, RequestAccountProxyForget, RequestChangeTonWalletContractVersion, RequestGetAllTonWalletContractVersion, ResponseGetAllTonWalletContractVersion, SWCommonAccountError } from '@subwallet/extension-base/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { KeyringPair$Meta, TonKeypairTypes, TonWalletContractVersion } from '@subwallet/keyring/types'; import { keyring } from '@subwallet/ui-keyring'; import { t } from 'i18next'; @@ -12,6 +13,8 @@ import { assert } from '@polkadot/util'; import { AccountBaseHandler } from './Base'; +const accountModifyHandlerLogger = createLogger('AccountModifyHandler'); + /** * @class AccountModifyHandler * @extends AccountBaseHandler @@ -47,7 +50,7 @@ export class AccountModifyHandler extends AccountBaseHandler { keyring.changeMasterPassword(newPassword, oldPassword); } catch (e) { - console.error(e); + accountModifyHandlerLogger.error('Error changing master password', e); return { errors: [t((e as Error).message)], @@ -73,7 +76,7 @@ export class AccountModifyHandler extends AccountBaseHandler { callback(); } catch (e) { - console.error(e); + accountModifyHandlerLogger.error('Error migrating master password', e); return { errors: [(e as Error).message], diff --git a/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts b/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts index da542485af8..e80d7dc3a99 100644 --- a/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts +++ b/packages/extension-base/src/services/keyring-service/context/handlers/Secret.ts @@ -3,6 +3,7 @@ import { AccountExternalError, AccountExternalErrorCode, RequestAccountCreateExternalV2, RequestAccountCreateWithSecretKey, RequestAccountExportPrivateKey, ResponseAccountCreateWithSecretKey, ResponseAccountExportPrivateKey } from '@subwallet/extension-base/background/KoniTypes'; import { AccountChainType, CommonAccountErrorType, RequestCheckPublicAndSecretKey, RequestPrivateKeyValidateV2, ResponseCheckPublicAndSecretKey, ResponsePrivateKeyValidateV2, SWCommonAccountError } from '@subwallet/extension-base/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { getKeypairTypeByAddress } from '@subwallet/keyring'; import { decodePair } from '@subwallet/keyring/pair/decode'; import { BitcoinKeypairTypes, CardanoKeypairTypes, KeypairType, KeyringPair, KeyringPair$Meta, TonKeypairTypes } from '@subwallet/keyring/types'; @@ -14,6 +15,8 @@ import { base64Decode, keyExtractSuri } from '@polkadot/util-crypto'; import { AccountBaseHandler } from './Base'; +const accountSecretHandlerLogger = createLogger('AccountSecretHandler'); + /** * @class AccountSecretHandler * @extends AccountBaseHandler @@ -246,7 +249,7 @@ export class AccountSecretHandler extends AccountBaseHandler { }; } } catch (e) { - console.error(e); + accountSecretHandlerLogger.error('Error checking public and secret key', e); return { address: '', diff --git a/packages/extension-base/src/services/keyring-service/context/state.ts b/packages/extension-base/src/services/keyring-service/context/state.ts index e33f3d77612..d38451617f8 100644 --- a/packages/extension-base/src/services/keyring-service/context/state.ts +++ b/packages/extension-base/src/services/keyring-service/context/state.ts @@ -6,6 +6,7 @@ import { ALL_ACCOUNT_KEY, UPGRADE_DUPLICATE_ACCOUNT_NAME } from '@subwallet/exte import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { AccountProxyStoreSubject, CurrentAccountStoreSubject, ModifyPairStoreSubject } from '@subwallet/extension-base/services/keyring-service/context/stores'; import { AuthUrls } from '@subwallet/extension-base/services/request-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { SWStorage } from '@subwallet/extension-base/storage'; import { AccountRefStore } from '@subwallet/extension-base/stores'; import { AccountMetadataData, AccountProxy, AccountProxyData, AccountProxyMap, AccountProxyStoreData, AccountProxyType, CurrentAccountInfo, ModifyPairStoreData } from '@subwallet/extension-base/types'; @@ -16,6 +17,8 @@ import { keyring } from '@subwallet/ui-keyring'; import { SubjectInfo } from '@subwallet/ui-keyring/observable/types'; import { BehaviorSubject, combineLatest, filter, first } from 'rxjs'; +const accountStateLogger = createLogger('AccountState'); + interface ExistsAccount { address: string; name: string; @@ -56,9 +59,9 @@ export class AccountState { this._modifyPair.init(); // Load account proxies this._accountProxy.init(); - this.subscribeAccounts().catch(console.error); + this.subscribeAccounts().catch((error) => accountStateLogger.error('Error subscribing accounts', error)); }) - .catch(console.error); + .catch((error) => accountStateLogger.error('Error initializing account state', error)); } private async subscribeAccounts () { @@ -121,7 +124,7 @@ export class AccountState { const accountNameDuplicates = this.getDuplicateAccountNames(transformedAccounts); if (accountNameDuplicates.length > 0) { - SWStorage.instance.setItem(UPGRADE_DUPLICATE_ACCOUNT_NAME, 'true').catch(console.error); + SWStorage.instance.setItem(UPGRADE_DUPLICATE_ACCOUNT_NAME, 'true').catch((error) => accountStateLogger.error('Error setting upgrade duplicate account name', error)); for (const accountProxy of transformedAccounts) { if (accountNameDuplicates.includes(accountProxy.name)) { @@ -728,11 +731,11 @@ export class AccountState { } public enableChain (slug: string) { - this.koniState.enableChain(slug, true).catch(console.error); + this.koniState.enableChain(slug, true).catch((error) => accountStateLogger.error('Error enabling chain', error)); } public enableChainWithPriorityAssets (slug: string) { - this.koniState.enableChainWithPriorityAssets(slug, true).catch(console.error); + this.koniState.enableChainWithPriorityAssets(slug, true).catch((error) => accountStateLogger.error('Error enabling chain with priority assets', error)); } /* Others */ diff --git a/packages/extension-base/src/services/keyring-service/index.ts b/packages/extension-base/src/services/keyring-service/index.ts index 9309d33998d..6a41d1a2636 100644 --- a/packages/extension-base/src/services/keyring-service/index.ts +++ b/packages/extension-base/src/services/keyring-service/index.ts @@ -3,11 +3,14 @@ import { KeyringState } from '@subwallet/extension-base/background/KoniTypes'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { keyring } from '@subwallet/ui-keyring'; import { BehaviorSubject } from 'rxjs'; import { AccountContext } from './context/account-context'; +const keyringServiceLogger = createLogger('KeyringService'); + export class KeyringService { private readonly stateSubject = new BehaviorSubject({ isReady: false, @@ -44,7 +47,7 @@ export class KeyringService { this.state.eventService.emit('keyring.ready', true); this.state.eventService.emit('account.ready', true); }) - .catch(console.error); + .catch((error) => keyringServiceLogger.error('Error waiting for crypto ready', error)); } this.stateSubject.next({ diff --git a/packages/extension-base/src/services/migration-service/Base.ts b/packages/extension-base/src/services/migration-service/Base.ts index 15b7d995d8b..43b71e3ee63 100644 --- a/packages/extension-base/src/services/migration-service/Base.ts +++ b/packages/extension-base/src/services/migration-service/Base.ts @@ -16,6 +16,6 @@ export default class BaseMigrationJob { } public run (): Promise { - return Promise.resolve(console.warn('Need to override function run from base.')); + return Promise.resolve(this.logger.warn('Need to override function run from base.')); } } diff --git a/packages/extension-base/src/services/migration-service/scripts/DeleteChain.ts b/packages/extension-base/src/services/migration-service/scripts/DeleteChain.ts index 78e6522303d..d1b171029f8 100644 --- a/packages/extension-base/src/services/migration-service/scripts/DeleteChain.ts +++ b/packages/extension-base/src/services/migration-service/scripts/DeleteChain.ts @@ -10,6 +10,6 @@ export default class DeleteChain extends BaseMigrationJob { this.state.forceRemoveChain(chain); }); - console.log('done job'); + this.logger.log('done job'); } } diff --git a/packages/extension-base/src/services/migration-service/scripts/DeleteChainStaking.ts b/packages/extension-base/src/services/migration-service/scripts/DeleteChainStaking.ts index 1238883560b..e760db3c014 100644 --- a/packages/extension-base/src/services/migration-service/scripts/DeleteChainStaking.ts +++ b/packages/extension-base/src/services/migration-service/scripts/DeleteChainStaking.ts @@ -8,7 +8,7 @@ export default class DeleteChainStaking extends BaseMigrationJob { try { await this.state.dbService.stores.yieldPoolInfo.table.where({ slug: 'CAPS___native_staking___ternoa_alphanet' }).delete(); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData.ts b/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData.ts index 03f79f25141..8dcc324fd9a 100644 --- a/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData.ts +++ b/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData.ts @@ -8,7 +8,7 @@ export default class DeleteEarningData extends BaseMigrationJob { try { await this.state.dbService.deleteYieldPoolInfo(['KILT___native_staking___kilt', 'PILT___native_staking___kilt_peregrine']); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251010.ts b/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251010.ts index c8d7e5880af..1d27ed14bbc 100644 --- a/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251010.ts +++ b/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251010.ts @@ -8,7 +8,7 @@ export default class DeleteEarningData20251010 extends BaseMigrationJob { try { await this.state.dbService.deleteYieldPoolInfo(['KSM___native_staking___kusama', 'KSM___nomination_pool___kusama']); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251105.ts b/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251105.ts index d5658f22dce..d950d00afd9 100644 --- a/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251105.ts +++ b/packages/extension-base/src/services/migration-service/scripts/DeleteEarningData20251105.ts @@ -8,7 +8,7 @@ export default class DeleteEarningData20251105 extends BaseMigrationJob { try { await this.state.dbService.deleteYieldPoolInfo(['DOT___native_staking___polkadot', 'DOT___nomination_pool___polkadot']); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/DisableZeroBalanceTokens.ts b/packages/extension-base/src/services/migration-service/scripts/DisableZeroBalanceTokens.ts index b7394506e0d..20567862d6c 100644 --- a/packages/extension-base/src/services/migration-service/scripts/DisableZeroBalanceTokens.ts +++ b/packages/extension-base/src/services/migration-service/scripts/DisableZeroBalanceTokens.ts @@ -60,7 +60,7 @@ export default class DisableZeroBalanceTokens extends BaseMigrationJob { state.chainService.setAssetSettings(updatedSettings); } catch (error) { - console.error(error); + this.logger.error(error); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/EnableEarningChains.ts b/packages/extension-base/src/services/migration-service/scripts/EnableEarningChains.ts index a7d49c5a2c8..5fd6c9cb20c 100644 --- a/packages/extension-base/src/services/migration-service/scripts/EnableEarningChains.ts +++ b/packages/extension-base/src/services/migration-service/scripts/EnableEarningChains.ts @@ -8,7 +8,7 @@ export default class EnableEarningChains extends BaseMigrationJob { try { await this.state.chainService.enableChains(['moonbeam', 'acala', 'bifrost_dot', 'interlay', 'parallel']); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateAuthUrls.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateAuthUrls.ts index 25ace3c2f8e..06175f8a83e 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateAuthUrls.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateAuthUrls.ts @@ -28,7 +28,7 @@ export default class MigrateSettings extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateAutoLock.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateAutoLock.ts index d2574ee306d..fd14082a451 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateAutoLock.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateAutoLock.ts @@ -18,7 +18,7 @@ export default class MigrateAutoLock extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateChainPatrol.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateChainPatrol.ts index 9b4b4d183ec..ee6fcee6ff0 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateChainPatrol.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateChainPatrol.ts @@ -18,7 +18,7 @@ export default class MigrateChainPatrol extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateImportedToken.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateImportedToken.ts index fe4505525ba..85e80490dd1 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateImportedToken.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateImportedToken.ts @@ -18,6 +18,7 @@ export default class MigrateImportedToken extends BaseMigrationJob { const state = this.state; return new Promise((resolve, reject) => { + const self = this; chrome.storage.local.get('EvmToken', function (items) { if (items && items.EvmToken) { const tokenMap = items.EvmToken as Record; @@ -42,7 +43,7 @@ export default class MigrateImportedToken extends BaseMigrationJob { icon: '' }); } catch (e) { - console.log(e); + self.logger.warn('Error migrating imported token', e); } }); }); diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateNewUnifiedAccount.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateNewUnifiedAccount.ts index 5e7a1777428..195c348e594 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateNewUnifiedAccount.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateNewUnifiedAccount.ts @@ -17,7 +17,7 @@ export default class MigrateNewUnifiedAccount extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateSettings.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateSettings.ts index b4a9c736d2f..bb3821a10e9 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateSettings.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateSettings.ts @@ -21,7 +21,7 @@ export default class MigrateSettings extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/MigrateWalletReference.ts b/packages/extension-base/src/services/migration-service/scripts/MigrateWalletReference.ts index f0aff318bdf..0732340d34d 100644 --- a/packages/extension-base/src/services/migration-service/scripts/MigrateWalletReference.ts +++ b/packages/extension-base/src/services/migration-service/scripts/MigrateWalletReference.ts @@ -20,7 +20,7 @@ export default class MigrateWalletReference extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/databases/AutoEnableSomeTokens.ts b/packages/extension-base/src/services/migration-service/scripts/databases/AutoEnableSomeTokens.ts index d440ccec83c..ddd6d47a5ce 100644 --- a/packages/extension-base/src/services/migration-service/scripts/databases/AutoEnableSomeTokens.ts +++ b/packages/extension-base/src/services/migration-service/scripts/databases/AutoEnableSomeTokens.ts @@ -17,7 +17,7 @@ export default class AutoEnableSomeTokens extends BaseMigrationJob { await this.state.chainService.updateAssetSetting(slug, { visible: true }, true); } } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting.ts b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting.ts index 39b344adc69..7ad9de05a50 100644 --- a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting.ts +++ b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting.ts @@ -28,7 +28,7 @@ export default class MigrateAssetSetting extends BaseMigrationJob { ...migratedAssetSetting }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251027.ts b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251027.ts index 6ff6dccead9..b7637b938e2 100644 --- a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251027.ts +++ b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251027.ts @@ -28,7 +28,7 @@ export default class MigrateAssetSetting20251027 extends BaseMigrationJob { ...migratedAssetSetting }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251107.ts b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251107.ts index 2af09b84ef5..3cc71492c78 100644 --- a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251107.ts +++ b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateAssetSetting20251107.ts @@ -28,7 +28,7 @@ export default class MigrateAssetSetting20251107 extends BaseMigrationJob { ...migratedAssetSetting }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningHistory.ts b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningHistory.ts index 5727adca2d5..c2f4b0c93e1 100644 --- a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningHistory.ts +++ b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningHistory.ts @@ -8,7 +8,7 @@ export default class MigrateEarningHistory extends BaseMigrationJob { try { await this.state.dbService.removeOldEarningData(); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningVersion.ts b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningVersion.ts index 9ec5aaa39eb..14d34818a58 100644 --- a/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningVersion.ts +++ b/packages/extension-base/src/services/migration-service/scripts/databases/MigrateEarningVersion.ts @@ -8,7 +8,7 @@ export default class MigrateEarningVersion extends BaseMigrationJob { try { await this.state.dbService.removeOldEarningData(); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/databases/ReloadMetadata.ts b/packages/extension-base/src/services/migration-service/scripts/databases/ReloadMetadata.ts index 5307b426b7d..d1dfbebcbf4 100644 --- a/packages/extension-base/src/services/migration-service/scripts/databases/ReloadMetadata.ts +++ b/packages/extension-base/src/services/migration-service/scripts/databases/ReloadMetadata.ts @@ -22,7 +22,7 @@ export default class ReloadMetadata extends BaseMigrationJob { this.state.chainService.disableChain(chain); setTimeout(() => { - this.state.chainService.enableChain(chain).catch(console.error); + this.state.chainService.enableChain(chain).catch((error) => this.logger.error('Error enabling chain', error)); }, 500); } } diff --git a/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccount.ts b/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccount.ts index f6531fdceff..8cf6e4d8232 100644 --- a/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccount.ts +++ b/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccount.ts @@ -31,7 +31,7 @@ export default class MigrateLedgerAccount extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccountV2.ts b/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccountV2.ts index 1480385acf8..f4fbf912519 100644 --- a/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccountV2.ts +++ b/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateLedgerAccountV2.ts @@ -43,7 +43,7 @@ export default class MigrateLedgerAccountV2 extends BaseMigrationJob { }); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/keyring/MigratePairData.ts b/packages/extension-base/src/services/migration-service/scripts/keyring/MigratePairData.ts index 78eb6c03185..09652b74f94 100644 --- a/packages/extension-base/src/services/migration-service/scripts/keyring/MigratePairData.ts +++ b/packages/extension-base/src/services/migration-service/scripts/keyring/MigratePairData.ts @@ -10,13 +10,13 @@ export default class MigratePairData extends BaseMigrationJob { try { this.state.keyringService.context.updateMetadataForPair(); } catch (e) { - console.error(e); + this.logger.error(e); } resolve(); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateRemoveGenesisHash.ts b/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateRemoveGenesisHash.ts index 5753866a13f..08cbc01bb6d 100644 --- a/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateRemoveGenesisHash.ts +++ b/packages/extension-base/src/services/migration-service/scripts/keyring/MigrateRemoveGenesisHash.ts @@ -10,13 +10,13 @@ export default class MigrateRemoveGenesisHash extends BaseMigrationJob { try { this.state.keyringService.context.removeNoneHardwareGenesisHash(); } catch (e) { - console.error(e); + this.logger.error(e); } resolve(); }); } catch (e) { - console.error(e); + this.logger.error(e); } } } diff --git a/packages/extension-base/src/services/mkt-campaign-service/index.ts b/packages/extension-base/src/services/mkt-campaign-service/index.ts index 544b44c1748..ba76d0a2160 100644 --- a/packages/extension-base/src/services/mkt-campaign-service/index.ts +++ b/packages/extension-base/src/services/mkt-campaign-service/index.ts @@ -4,11 +4,14 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { _getAssetDecimals, _getChainNativeTokenBasicInfo } from '@subwallet/extension-base/services/chain-service/utils'; import { AppBannerData, AppBasicInfoData, AppCommonData, AppConfirmationData, AppPopupData, ConditionBalanceType, ConditionCrowdloanType, ConditionEarningType, ConditionHasMoneyType, ConditionNftType, ConditionType, MktCampaignCondition, MktCampaignConditionTypeValue } from '@subwallet/extension-base/services/mkt-campaign-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { fetchStaticData, TARGET_ENV, wait } from '@subwallet/extension-base/utils'; import { keyring } from '@subwallet/ui-keyring'; import BigN from 'bignumber.js'; import { BehaviorSubject } from 'rxjs'; +const mktCampaignServiceLogger = createLogger('MktCampaignService'); + export default class MktCampaignService { readonly #state: KoniState; @@ -23,30 +26,30 @@ export default class MktCampaignService { this.appConfirmationSubject.next([]); this.fetchPopupData().catch((e) => { - console.error('Error on fetch popup', e); + mktCampaignServiceLogger.error('Error on fetch popup', e); }); this.fetchBannerData().catch((e) => { - console.error('Error on fetch banner', e); + mktCampaignServiceLogger.error('Error on fetch banner', e); }); this.fetchConfirmationData().catch((e) => { - console.error('Error on fetch confirmation', e); + mktCampaignServiceLogger.error('Error on fetch confirmation', e); }); } fetchMktCampaignData (timeout = 10000) { wait(timeout) .finally(() => { - this.fetchPopupData().catch(console.error); - this.fetchBannerData().catch(console.error); - this.fetchConfirmationData().catch(console.error); + this.fetchPopupData().catch((error) => mktCampaignServiceLogger.error('Error fetching popup data', error)); + this.fetchBannerData().catch((error) => mktCampaignServiceLogger.error('Error fetching banner data', error)); + this.fetchConfirmationData().catch((error) => mktCampaignServiceLogger.error('Error fetching confirmation data', error)); }); } public init () { this.fetchMktCampaignData(); - console.log('Mkt campaign service ready'); + mktCampaignServiceLogger.info('Mkt campaign service ready'); } public async fetchPopupData () { diff --git a/packages/extension-base/src/services/nft-service/index.ts b/packages/extension-base/src/services/nft-service/index.ts index e7699fe513b..1fb3a33e649 100644 --- a/packages/extension-base/src/services/nft-service/index.ts +++ b/packages/extension-base/src/services/nft-service/index.ts @@ -5,12 +5,15 @@ import { _AssetType } from '@subwallet/chain-list/types'; import { NftCollection, NftFullListRequest, NftItem } from '@subwallet/extension-base/background/KoniTypes'; import KoniState from '@subwallet/extension-base/koni/background/handlers/State'; import { _getEvmChainId } from '@subwallet/extension-base/services/chain-service/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { baseParseIPFSUrl } from '@subwallet/extension-base/utils'; import { getKeypairTypeByAddress } from '@subwallet/keyring'; import { EthereumKeypairTypes } from '@subwallet/keyring/types'; import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk'; import { BlockscoutNftInstanceRaw } from '@subwallet-monorepos/subwallet-services-sdk/services/blockscout/types'; +const nftServiceLogger = createLogger('NftService'); + /** * NFT detection service * Responsible for managing NFT detection jobs per address @@ -137,7 +140,7 @@ export default class NftService { if (typeValid) { if (this.inProgress.has(address)) { - console.log(`[NftService] ${address} already running`); + nftServiceLogger.debug(`${address} already running`); continue; } @@ -148,7 +151,7 @@ export default class NftService { const nftDetectionApi = subwalletApiSdk.nftDetectionApi; if (!nftDetectionApi?.getEvmNftCollectionsByAddress) { - console.warn('[NftService] NftDetectionApi not available'); + nftServiceLogger.warn('NftDetectionApi not available'); continue; } @@ -181,7 +184,7 @@ export default class NftService { await this.state.handleDetectedNftCollections(allCollections); await this.state.handleDetectedNfts(address, allItems); } catch (err) { - console.warn(`[NftService] detect error for ${address}`, err); + nftServiceLogger.warn(`detect error for ${address}`, err); } finally { this.inProgress.delete(address); } @@ -194,7 +197,7 @@ export default class NftService { const chainId = _getEvmChainId(chainInfo); if (!contractAddress || !owners || !chainId) { - console.warn('[NftService] missing params for getFullNftInstancesByCollection'); + nftServiceLogger.warn('missing params for getFullNftInstancesByCollection'); return false; } @@ -203,7 +206,7 @@ export default class NftService { const nftDetectionApi = subwalletApiSdk.nftDetectionApi; if (!nftDetectionApi?.getAllNftInstances) { - console.warn('[NftService] getAllNftInstances not available'); + nftServiceLogger.warn('getAllNftInstances not available'); return false; } @@ -222,24 +225,24 @@ export default class NftService { continue; } - console.log('FOR TESTER (before)', instances); + nftServiceLogger.debug('FOR TESTER (before)', instances); const nftList = instances.map((inst) => mapSdkToNftItem(inst, chainInfo.slug, contractAddress, eachOwner) ).filter((i): i is NftItem => Boolean(i)); - console.log('FOR TESTER (after)', nftList); + nftServiceLogger.debug('FOR TESTER (after)', nftList); await this.state.handleDetectedNfts(eachOwner, nftList); } catch (innerErr) { - console.warn(`[NftService] getAllNftInstances failed for ${eachOwner}`, innerErr); + nftServiceLogger.warn(`getAllNftInstances failed for ${eachOwner}`, innerErr); } } return true; } catch (err) { - console.error( - `[NftDetectionService] getFullNftInstancesByCollection error for ${contractAddress}`, + nftServiceLogger.error( + `getFullNftInstancesByCollection error for ${contractAddress}`, err ); diff --git a/packages/extension-base/src/services/notification-service/NotificationService.ts b/packages/extension-base/src/services/notification-service/NotificationService.ts index bb781791f1f..bd7debbe1d7 100644 --- a/packages/extension-base/src/services/notification-service/NotificationService.ts +++ b/packages/extension-base/src/services/notification-service/NotificationService.ts @@ -2,9 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 import { Notification, NotificationButton, NotificationParams } from '@subwallet/extension-base/background/KoniTypes'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isFirefox } from '@subwallet/extension-base/utils'; import { BehaviorSubject } from 'rxjs'; +const notificationServiceLogger = createLogger('NotificationService'); + export default class NotificationService { private notificationSubject = new BehaviorSubject([]); @@ -52,7 +55,7 @@ export default class NotificationService { if (onClick) { onClick(); } else { - chrome.tabs.create({ url: link }).catch(console.error); + chrome.tabs.create({ url: link }).catch((error) => notificationServiceLogger.error('Error creating notification tab', error)); } } }); diff --git a/packages/extension-base/src/services/price-service/coingecko.ts b/packages/extension-base/src/services/price-service/coingecko.ts index 3d934e9cb70..86f4f58eb37 100644 --- a/packages/extension-base/src/services/price-service/coingecko.ts +++ b/packages/extension-base/src/services/price-service/coingecko.ts @@ -3,11 +3,14 @@ import { CurrencyJson, CurrencyType, ExchangeRateJSON, HistoryTokenPriceJSON, PriceChartTimeframe, PriceJson } from '@subwallet/extension-base/background/KoniTypes'; import { isProductionMode } from '@subwallet/extension-base/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { staticData, StaticKey } from '@subwallet/extension-base/utils/staticData'; import subwalletApiSdk from '@subwallet-monorepos/subwallet-services-sdk'; import { isArray } from '@polkadot/util'; +const priceServiceLogger = createLogger('PriceService'); + interface GeckoItem { id: string, name: string, @@ -95,7 +98,7 @@ const fetchDerivativeTokenSlugs = async () => { return new Set(apiSlugs.length > 0 ? apiSlugs : DERIVATIVE_TOKEN_SLUG_LIST); } catch (error) { - console.error('Error fetching derivative token slugs from API:', error); + priceServiceLogger.error('Error fetching derivative token slugs from API:', error); return new Set(DERIVATIVE_TOKEN_SLUG_LIST); } @@ -123,11 +126,11 @@ export const getPriceMap = async (priceIds: Set, currency: CurrencyType } }); } else { - console.warn('Invalid data from derivative API:', generateDerivativePriceRaw); + priceServiceLogger.warn('Invalid data from derivative API:', generateDerivativePriceRaw); derivativeApiError = true; } } catch (error) { - console.error('Error fetching derivative API:', error); + priceServiceLogger.error('Error fetching derivative API:', error); derivativeApiError = true; } } @@ -207,7 +210,7 @@ export const getHistoryPrice = async (priceId: string, type: PriceChartTimeframe return response; } } catch (e) { - console.error('Error fetching price history:', e); + priceServiceLogger.error('Error fetching price history:', e); } return { history: [] }; diff --git a/packages/extension-base/src/services/price-service/index.ts b/packages/extension-base/src/services/price-service/index.ts index 2fefe2f8cd0..f53366b99be 100644 --- a/packages/extension-base/src/services/price-service/index.ts +++ b/packages/extension-base/src/services/price-service/index.ts @@ -13,8 +13,10 @@ import { CurrentCurrencyStore } from '@subwallet/extension-base/stores'; import { getTokenPriceHistoryId, TIME_INTERVAL, wait } from '@subwallet/extension-base/utils'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; import { staticData, StaticKey } from '@subwallet/extension-base/utils/staticData'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BehaviorSubject, combineLatest, distinctUntilChanged, map, Subject } from 'rxjs'; +const priceServiceLogger = createLogger('PriceService'); const DEFAULT_CURRENCY: CurrencyType = 'USD'; const DEFAULT_PRICE_SUBJECT: PriceJson = { currency: DEFAULT_CURRENCY, @@ -58,12 +60,12 @@ export class PriceService implements StoppableServiceInterface, PersistDataServi SWStorage.instance.getItem(CURRENCY) .then((currency) => { this.setCurrentCurrency(currency as CurrencyType || currentCurrency || DEFAULT_CURRENCY); - }).catch(console.error); + }).catch((error) => priceServiceLogger.error('Error getting currency', error)); }; this.init().then( () => this.getCurrentCurrency(updateCurrency) - ).catch(console.error); + ).catch((error) => priceServiceLogger.error('Error initializing price service', error)); } private async getTokenPrice (priceIds: Set, currency?: CurrencyType, resolve?: (rs: boolean) => void, reject?: (e: boolean) => void) { @@ -115,7 +117,7 @@ export class PriceService implements StoppableServiceInterface, PersistDataServi this.priceSubject.next(newPriceMap); } } catch (e) { - console.error(e); + priceServiceLogger.error('Error in price service', e); } finally { this.refreshPromise = null; } @@ -203,7 +205,7 @@ export class PriceService implements StoppableServiceInterface, PersistDataServi this.refreshPriceMapByAction(); }) .catch((e) => { - console.error(e); + priceServiceLogger.error('Error in price service', e); }); this.refreshTimeout = setTimeout(this.refreshPriceData.bind(this), CRON_REFRESH_PRICE_INTERVAL); @@ -309,7 +311,7 @@ export class PriceService implements StoppableServiceInterface, PersistDataServi if (data) { this.priceSubject.next(data); } - }).catch(console.error); + }).catch((error) => priceServiceLogger.error('Error calculating price map', error)); }); this.status = ServiceStatus.INITIALIZED; @@ -334,7 +336,7 @@ export class PriceService implements StoppableServiceInterface, PersistDataServi } async persistData (): Promise { - await this.dbService.updatePriceStore(this.priceSubject.value).catch(console.error); + await this.dbService.updatePriceStore(this.priceSubject.value).catch((error) => priceServiceLogger.error('Error updating price store', error)); } startPromiseHandler = createPromiseHandler(); diff --git a/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts index 1162a325365..fc010bc179f 100644 --- a/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/AuthRequestHandler.ts @@ -11,6 +11,7 @@ import { KeyringService } from '@subwallet/extension-base/services/keyring-servi import RequestService from '@subwallet/extension-base/services/request-service'; import { DAPP_CONNECT_BOTH_TYPE_ACCOUNT_URL, PREDEFINED_CHAIN_DAPP_CHAIN_MAP, WEB_APP_URL } from '@subwallet/extension-base/services/request-service/constants'; import { AuthUrlInfoNeedMigration, AuthUrls } from '@subwallet/extension-base/services/request-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import AuthorizeStore from '@subwallet/extension-base/stores/Authorize'; import { createPromiseHandler, getDomainFromUrl, PromiseHandler, stripUrl } from '@subwallet/extension-base/utils'; import { getId } from '@subwallet/extension-base/utils/getId'; @@ -20,6 +21,8 @@ import { BehaviorSubject } from 'rxjs'; import { isEthereumAddress } from '@polkadot/util-crypto'; +const authRequestHandlerLogger = createLogger('AuthRequestHandler'); + const AUTH_URLS_KEY = 'authUrls'; export default class AuthRequestHandler { @@ -36,8 +39,8 @@ export default class AuthRequestHandler { this.#requestService = requestService; this.#chainService = chainService; this.migrateAuthUrlInfoToUnified().then(() => { - this.init().catch(console.error); - }).catch(console.error); + this.init().catch((error) => authRequestHandlerLogger.error('Error initializing auth request handler', error)); + }).catch((error) => authRequestHandlerLogger.error('Error migrating auth URL info', error)); } private async init () { diff --git a/packages/extension-base/src/services/request-service/handler/BitcoinRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/BitcoinRequestHandler.ts index 087325ab9cd..0c6d0eeb360 100644 --- a/packages/extension-base/src/services/request-service/handler/BitcoinRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/BitcoinRequestHandler.ts @@ -10,6 +10,8 @@ import RequestService from '@subwallet/extension-base/services/request-service'; import TransactionService from '@subwallet/extension-base/services/transaction-service'; import { TransactionEventResponse } from '@subwallet/extension-base/services/transaction-service/types'; import { BasicTxErrorType } from '@subwallet/extension-base/types'; + +const bitcoinRequestHandlerLogger = createLogger('BitcoinRequestHandler'); import { createPromiseHandler } from '@subwallet/extension-base/utils'; import { isInternalRequest } from '@subwallet/extension-base/utils/request'; import keyring from '@subwallet/ui-keyring'; @@ -432,7 +434,7 @@ export default class BitcoinRequestHandler { const { resolver } = this.confirmationsPromiseMap[id]; if (!resolver || !confirmation) { - console.error('Not found confirmation', type, id); + bitcoinRequestHandlerLogger.error('Not found confirmation', type, id); } else { resolver.reject(new Error('Reset wallet')); } diff --git a/packages/extension-base/src/services/request-service/handler/CardanoRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/CardanoRequestHandler.ts index cdf53409fec..9a4c9349df8 100644 --- a/packages/extension-base/src/services/request-service/handler/CardanoRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/CardanoRequestHandler.ts @@ -5,17 +5,16 @@ import { FixedTransaction, TransactionWitnessSet, Vkeywitnesses } from '@emurgo/ import { ConfirmationDefinitionsCardano, ConfirmationsQueueCardano, ConfirmationsQueueItemOptions, ConfirmationTypeCardano, RequestConfirmationCompleteCardano, ResponseCardanoSignData } from '@subwallet/extension-base/background/KoniTypes'; import { ConfirmationRequestBase, Resolver } from '@subwallet/extension-base/background/types'; import RequestService from '@subwallet/extension-base/services/request-service'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isInternalRequest } from '@subwallet/extension-base/utils/request'; import { keyring } from '@subwallet/ui-keyring'; import { t } from 'i18next'; import { BehaviorSubject } from 'rxjs'; -import { logger as createLogger } from '@polkadot/util/logger'; -import { Logger } from '@polkadot/util/types'; +const cardanoRequestHandlerLogger = createLogger('CardanoRequestHandler'); export default class CardanoRequestHandler { readonly #requestService: RequestService; - readonly #logger: Logger; private readonly confirmationsQueueSubjectCardano = new BehaviorSubject({ cardanoSignatureRequest: {}, @@ -28,7 +27,6 @@ export default class CardanoRequestHandler { constructor (requestService: RequestService) { this.#requestService = requestService; - this.#logger = createLogger('CardanoRequestHandler'); } public get numCardanoRequests (): number { @@ -115,7 +113,7 @@ export default class CardanoRequestHandler { const confirmation = confirmations[type][id]; if (!resolver || !confirmation) { - this.#logger.error(t('bg.DAPP.services.service.request.CardanoHandler.unableToProceed'), type, id); + cardanoRequestHandlerLogger.error(t('bg.DAPP.services.service.request.CardanoHandler.unableToProceed'), type, id); throw new Error(t('bg.DAPP.services.service.request.CardanoHandler.unableToProceed')); } @@ -222,7 +220,7 @@ export default class CardanoRequestHandler { const { resolver } = this.confirmationsPromiseMap[id]; if (!resolver || !confirmation) { - console.error('Not found confirmation', type, id); + cardanoRequestHandlerLogger.error('Not found confirmation', type, id); } else { resolver.reject(new Error('Reset wallet')); } diff --git a/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts index cf863aca2a3..f80ee734bc8 100644 --- a/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/EvmRequestHandler.ts @@ -10,6 +10,8 @@ import RequestService from '@subwallet/extension-base/services/request-service'; import { anyNumberToBN } from '@subwallet/extension-base/utils/eth'; import { isInternalRequest } from '@subwallet/extension-base/utils/request'; import keyring from '@subwallet/ui-keyring'; + +const evmRequestHandlerLogger = createLogger('EvmRequestHandler'); import BigN from 'bignumber.js'; import BN from 'bn.js'; import { toBuffer } from 'ethereumjs-util'; @@ -305,7 +307,7 @@ export default class EvmRequestHandler { const { resolver } = this.confirmationsPromiseMap[id]; if (!resolver || !confirmation) { - console.error('Not found confirmation', type, id); + evmRequestHandlerLogger.error('Not found confirmation', type, id); } else { resolver.reject(new Error('Reset wallet')); } diff --git a/packages/extension-base/src/services/request-service/handler/TonRequestHandler.ts b/packages/extension-base/src/services/request-service/handler/TonRequestHandler.ts index 81cd419d251..14406cc2720 100644 --- a/packages/extension-base/src/services/request-service/handler/TonRequestHandler.ts +++ b/packages/extension-base/src/services/request-service/handler/TonRequestHandler.ts @@ -11,6 +11,8 @@ import { t } from 'i18next'; import { BehaviorSubject } from 'rxjs'; import { u8aToHex } from '@polkadot/util'; + +const tonRequestHandlerLogger = createLogger('TonRequestHandler'); import { logger as createLogger } from '@polkadot/util/logger'; import { Logger } from '@polkadot/util/types'; @@ -186,7 +188,7 @@ export default class TonRequestHandler { const { resolver } = this.confirmationsPromiseMap[id]; if (!resolver || !confirmation) { - console.error('Not found confirmation', type, id); + tonRequestHandlerLogger.error('Not found confirmation', type, id); } else { resolver.reject(new Error('Reset wallet')); } diff --git a/packages/extension-base/src/services/request-service/index.ts b/packages/extension-base/src/services/request-service/index.ts index 13f4029edee..af8333800e3 100644 --- a/packages/extension-base/src/services/request-service/index.ts +++ b/packages/extension-base/src/services/request-service/index.ts @@ -11,10 +11,13 @@ import SettingService from '@subwallet/extension-base/services/setting-service/S import TransactionService from '@subwallet/extension-base/services/transaction-service'; import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types'; import { MetadataDef } from '@subwallet/extension-inject/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BehaviorSubject } from 'rxjs'; import { SignerPayloadJSON } from '@polkadot/types/types/extrinsic'; +const requestServiceLogger = createLogger('RequestService'); + import TonRequestHandler from './handler/TonRequestHandler'; import { AuthRequestHandler, ConnectWCRequestHandler, EvmRequestHandler, MetadataRequestHandler, NotSupportWCRequestHandler, PopupHandler, SubstrateRequestHandler } from './handler'; import { AuthUrls, MetaRequest } from './types'; @@ -83,7 +86,7 @@ export default class RequestService { const popupList = this.#popupHandler.popup; if (popupList && popupList.length > 0) { - chrome.windows.update(popupList[0], { focused: true })?.catch(console.error); + chrome.windows.update(popupList[0], { focused: true })?.catch((error) => requestServiceLogger.error('Error updating popup window', error)); } else { this.#popupHandler.popupOpen(); } diff --git a/packages/extension-base/src/services/setting-service/SettingService.ts b/packages/extension-base/src/services/setting-service/SettingService.ts index d4e640bdac3..af6419b7076 100644 --- a/packages/extension-base/src/services/setting-service/SettingService.ts +++ b/packages/extension-base/src/services/setting-service/SettingService.ts @@ -8,11 +8,14 @@ import { SWStorage } from '@subwallet/extension-base/storage'; import ChainlistStore, { ChainlistConfig } from '@subwallet/extension-base/stores/ChainlistStore'; import PassPhishingStore from '@subwallet/extension-base/stores/PassPhishingStore'; import SettingsStore from '@subwallet/extension-base/stores/Settings'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { Subject } from 'rxjs'; import i18n from './i18n/i18n'; import { DEFAULT_SETTING } from './constants'; +const settingServiceLogger = createLogger('SettingService'); + export default class SettingService { private readonly settingsStore = new SettingsStore(); private readonly passPhishingStore = new PassPhishingStore(); @@ -20,7 +23,7 @@ export default class SettingService { private readonly environmentStore = new EnvironmentStoreSubject(); constructor () { - this.initSetting().catch(console.error); + this.initSetting().catch((error) => settingServiceLogger.error('Error initializing settings', error)); } private async initSetting () { @@ -29,7 +32,7 @@ export default class SettingService { const updateLanguage = ({ language }: UiSettings) => { if (language !== old) { old = language; - i18n.changeLanguage(language).catch(console.error); + i18n.changeLanguage(language).catch((error) => settingServiceLogger.error('Error changing language', error)); } }; diff --git a/packages/extension-base/src/services/setting-service/i18n/i18n.ts b/packages/extension-base/src/services/setting-service/i18n/i18n.ts index e40e8ffc340..e5a13d7f2d8 100644 --- a/packages/extension-base/src/services/setting-service/i18n/i18n.ts +++ b/packages/extension-base/src/services/setting-service/i18n/i18n.ts @@ -1,10 +1,13 @@ // Copyright 2019-2022 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { createLogger } from '@subwallet/extension-base/utils/logger'; import i18next from 'i18next'; import Backend from './Backend'; +const i18nLogger = createLogger('I18n'); + i18next.use(Backend).init({ backend: {}, debug: false, @@ -18,6 +21,6 @@ i18next.use(Backend).init({ nsSeparator: false, returnEmptyString: false, returnNull: false -}).catch(console.error); +}).catch((error) => i18nLogger.error('Error initializing i18n', error)); export default i18next; diff --git a/packages/extension-base/src/services/storage-service/db-stores/Crowdloan.ts b/packages/extension-base/src/services/storage-service/db-stores/Crowdloan.ts index 7a45a515502..d9572a85949 100644 --- a/packages/extension-base/src/services/storage-service/db-stores/Crowdloan.ts +++ b/packages/extension-base/src/services/storage-service/db-stores/Crowdloan.ts @@ -1,10 +1,13 @@ // Copyright 2019-2022 @subwallet/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { createLogger } from '@subwallet/extension-base/utils/logger'; import BaseStoreWithAddressAndChain from '@subwallet/extension-base/services/storage-service/db-stores/BaseStoreWithAddressAndChain'; import { ICrowdloanItem } from '../databases'; +const crowdloanStoreLogger = createLogger('CrowdloanStore'); + export default class CrowdloanStore extends BaseStoreWithAddressAndChain { async removeEndedCrowdloans () { const now = new Date(); @@ -16,7 +19,7 @@ export default class CrowdloanStore extends BaseStoreWithAddressAndChain { async getNotificationInfo (id: string) { return this.table.get(id); @@ -51,7 +54,7 @@ export default class InappNotificationStore extends BaseStore<_NotificationInfo> item.proxyId = newProxyId; item.title = item.title.replace(/\[.*?\]/, `[${newName}]`); }) - .catch(console.error); + .catch((error) => inappNotificationStoreLogger.error('Error updating notification proxy ID', error)); } async cleanUpOldNotifications (overdueTime: number) { diff --git a/packages/extension-base/src/services/swap-service/handler/base-handler.ts b/packages/extension-base/src/services/swap-service/handler/base-handler.ts index 63d2b5a19e3..382557031e6 100644 --- a/packages/extension-base/src/services/swap-service/handler/base-handler.ts +++ b/packages/extension-base/src/services/swap-service/handler/base-handler.ts @@ -27,6 +27,9 @@ import BigN from 'bignumber.js'; import { t } from 'i18next'; import { isEthereumAddress } from '@polkadot/util-crypto'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const swapBaseHandlerLogger = createLogger('SwapBaseHandler'); import { createAcrossBridgeExtrinsic } from '../../balance-service/transfer/xcm'; @@ -246,7 +249,7 @@ export class SwapBaseHandler { if (needEditAmount) { bnSendingValue = BigN(selectedQuote.toAmount).multipliedBy(DEFAULT_EXCESS_AMOUNT_WEIGHT); // need to round } else { // todo: remove - console.log('The code cannot run into here, if it runs into here, pls ask dev to check'); + swapBaseHandlerLogger.warn('The code cannot run into here, if it runs into here, pls ask dev to check'); bnSendingValue = BigN(selectedQuote.toAmount); } } @@ -271,7 +274,7 @@ export class SwapBaseHandler { return [step, fee]; } catch (e) { - console.error('Error creating xcm step', e); + swapBaseHandlerLogger.error('Error creating xcm step', e); return undefined; } diff --git a/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts b/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts index 76624ea28f1..22049e75c0e 100644 --- a/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts +++ b/packages/extension-base/src/services/swap-service/handler/chainflip-handler.ts @@ -19,9 +19,12 @@ import BigNumber from 'bignumber.js'; import * as bitcoin from 'bitcoinjs-lib'; import { SubmittableExtrinsic } from '@polkadot/api/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { SWTransaction } from '../../transaction-service/types'; +const chainflipHandlerLogger = createLogger('ChainflipHandler'); + interface DepositAddressResponse { id: number; address: string; @@ -149,7 +152,7 @@ export class ChainflipSwapHandler implements SwapBaseInterface { const data = await response.json() as DepositAddressResponse; - console.log('Chainflip channel info:', data); + chainflipHandlerLogger.debug('Chainflip channel info', data); if (!data.id || !data.address || data.address === '' || !data.issuedBlock || !data.network || !data.channelId) { throw new Error('Error get Chainflip data'); diff --git a/packages/extension-base/src/services/swap-service/handler/kyber-handler.ts b/packages/extension-base/src/services/swap-service/handler/kyber-handler.ts index c34b5588628..37f4bd0ec79 100644 --- a/packages/extension-base/src/services/swap-service/handler/kyber-handler.ts +++ b/packages/extension-base/src/services/swap-service/handler/kyber-handler.ts @@ -12,8 +12,11 @@ import { getId } from '@subwallet/extension-base/utils/getId'; import BigNumber from 'bignumber.js'; import { TransactionConfig } from 'web3-core'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BalanceService } from '../../balance-service'; import { ChainService } from '../../chain-service'; + +const kyberHandlerLogger = createLogger('KyberHandler'); import { _getChainNativeTokenSlug, _getContractAddressOfToken, _isNativeToken } from '../../chain-service/utils'; import FeeService from '../../fee-service/service'; import { calculateGasFeeParams } from '../../fee-service/utils'; @@ -83,7 +86,7 @@ async function buildTxForKyberSwap (params: BuildTxForSwapParams, chain: string) const { recipient, sender, slippageTolerance } = params; let routeSummary = params.routeSummary; - console.log('routeSummary1', routeSummary); + kyberHandlerLogger.debug('routeSummary1', routeSummary); if (!routeSummary || !routeSummary.tokenIn || !routeSummary.tokenOut || !routeSummary.amountIn) { return { @@ -125,7 +128,7 @@ async function buildTxForKyberSwap (params: BuildTxForSwapParams, chain: string) routeSummary = routeData.data.routeSummary; } catch (error) { - console.error('Error:', error); + kyberHandlerLogger.error('Error in Kyber handler', error); return { error: new TransactionError(BasicTxErrorType.INTERNAL_ERROR, 'Unable to build Kyber swap transaction') }; } @@ -139,7 +142,7 @@ async function buildTxForKyberSwap (params: BuildTxForSwapParams, chain: string) enableGasEstimation: true }; - console.log('routeSummary2', routeSummary); + kyberHandlerLogger.debug('routeSummary2', routeSummary); try { const res = await fetchFromProxyService(ProxyServiceRoute.KYBER, `/${chain}/api/v1/route/build`, { @@ -179,7 +182,7 @@ async function buildTxForKyberSwap (params: BuildTxForSwapParams, chain: string) } }; } catch (error) { - console.error('Kyber error:', error); + kyberHandlerLogger.error('Kyber error', error); return { error: new TransactionError(BasicTxErrorType.INTERNAL_ERROR) }; } @@ -391,7 +394,7 @@ export class KyberHandler implements SwapBaseInterface { const rawTx = await buildTxForKyberSwap({ routeSummary: metadata.routeSummary, sender: params.address, recipient, slippageTolerance }, metadata.network); if (rawTx.error) { - console.error('Kyber error:', rawTx.error); + kyberHandlerLogger.error('Kyber error', rawTx.error); throw rawTx.error; } diff --git a/packages/extension-base/src/services/swap-service/handler/optimex-handler.ts b/packages/extension-base/src/services/swap-service/handler/optimex-handler.ts index c5146e05651..10fe2cc7a92 100644 --- a/packages/extension-base/src/services/swap-service/handler/optimex-handler.ts +++ b/packages/extension-base/src/services/swap-service/handler/optimex-handler.ts @@ -21,6 +21,9 @@ import BigNumber from 'bignumber.js'; import * as bitcoin from 'bitcoinjs-lib'; import { hexStripPrefix, u8aToHex } from '@polkadot/util'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const optimexHandlerLogger = createLogger('OptimexHandler'); interface OptimexQuoteMetadata { session_id: string; @@ -187,7 +190,7 @@ export class OptimexHandler implements SwapBaseInterface { }); if (!rawResponse.ok) { - console.log('Error bad request while init quote'); + optimexHandlerLogger.error('Error bad request while init quote'); return undefined; } @@ -196,7 +199,7 @@ export class OptimexHandler implements SwapBaseInterface { tradeInfo = response.data; } catch (e) { - console.log('Error while init quote'); + optimexHandlerLogger.error('Error while init quote'); return undefined; } @@ -233,7 +236,7 @@ export class OptimexHandler implements SwapBaseInterface { const depositAddress = this.currentTradeMetadata?.deposit_address; if (!depositAddress) { - console.log('Optimex Trade metadata is undefined, request for new quote'); + optimexHandlerLogger.warn('Optimex Trade metadata is undefined, request for new quote'); return Promise.resolve(undefined); } @@ -303,7 +306,7 @@ export class OptimexHandler implements SwapBaseInterface { networkFeeAmount = Math.ceil(feeCombine.feeRate * sizeInfo.txVBytes).toString(); } else { - console.log('Unsupported swap from this chain type', originChainType); + optimexHandlerLogger.warn('Unsupported swap from this chain type', originChainType); return Promise.resolve(undefined); } @@ -437,8 +440,8 @@ export class OptimexHandler implements SwapBaseInterface { let extrinsic: SWTransaction['transaction']; // dont remove this log - console.log('Optimex Trade metadata:', this.currentTradeMetadata); - console.log('Optimex Trade channel:', this.isTestnet ? `https://provider-api-docs.vercel.app/swap/${tradeId}` : `https://provider-api-docs.vercel.app/swap/${tradeId}?env=sub_wallet`); + optimexHandlerLogger.debug('Optimex Trade metadata', this.currentTradeMetadata); + optimexHandlerLogger.debug('Optimex Trade channel', this.isTestnet ? `https://provider-api-docs.vercel.app/swap/${tradeId}` : `https://provider-api-docs.vercel.app/swap/${tradeId}?env=sub_wallet`); if (chainType === ChainType.BITCOIN) { const bitcoinApi = this.chainService.getBitcoinApi(chainInfo.slug); diff --git a/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts b/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts index c104c153ba2..967b050bd4b 100644 --- a/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts +++ b/packages/extension-base/src/services/swap-service/handler/simpleswap-handler.ts @@ -14,8 +14,11 @@ import { getId } from '@subwallet/extension-base/utils/getId'; import BigN, { BigNumber } from 'bignumber.js'; import { SubmittableExtrinsic } from '@polkadot/api/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { BalanceService } from '../../balance-service'; + +const simpleSwapHandlerLogger = createLogger('SimpleSwapHandler'); import { getERC20TransactionObject, getEVMTransactionObject } from '../../balance-service/transfer/smart-contract'; import { createSubstrateExtrinsic } from '../../balance-service/transfer/token'; import { ChainService } from '../../chain-service'; @@ -101,7 +104,7 @@ const buildTxForSimpleSwap = async (params: BuildSimpleSwapTxParams): Promise action.action === DynamicSwapType.SWAP); if (!swapPairInfo) { - console.error('Swap pair is not found'); + logger.error('Swap pair is not found'); return result; } @@ -152,15 +155,15 @@ export class SwapService implements StoppableServiceInterface { const { path, swapQuoteResponse } = await this.getLatestQuoteFromSwapRequest(request); - console.group('Swap Logger'); - console.log('path', path); - console.log('swapQuoteResponse', swapQuoteResponse); + logger.group('Swap Logger'); + logger.info('path', path); + logger.info('swapQuoteResponse', swapQuoteResponse); if (swapQuoteResponse.optimalQuote && swapQuoteResponse.optimalQuote.metadata) { const routing = (swapQuoteResponse.optimalQuote.metadata as UniswapMetadata).routing; if (routing) { - console.log('Uniswap routing', routing); + logger.info('Uniswap routing', routing); } } @@ -190,8 +193,8 @@ export class SwapService implements StoppableServiceInterface { }; } - console.log('optimalProcess', optimalProcess); - console.groupEnd(); + logger.info('optimalProcess', optimalProcess); + logger.groupEnd(); if (JSON.stringify(processStepsToPathActions(optimalProcess.steps)) !== JSON.stringify(optimalProcess.path.map((e) => e.action))) { throw new Error('Swap pair is not found'); @@ -209,7 +212,7 @@ export class SwapService implements StoppableServiceInterface { try { availablePath = await subwalletApiSdk.swapApi.findAvailablePath(request); } catch (e) { - console.log('Error findAvailablePath', e); + logger.error('Error findAvailablePath', e); } if (!availablePath) { diff --git a/packages/extension-base/src/services/swap-service/utils.ts b/packages/extension-base/src/services/swap-service/utils.ts index fe5ba8d36bf..f6f9d1e45be 100644 --- a/packages/extension-base/src/services/swap-service/utils.ts +++ b/packages/extension-base/src/services/swap-service/utils.ts @@ -5,8 +5,11 @@ import { _ChainAsset } from '@subwallet/chain-list/types'; import { _getOriginChainOfAsset, _parseAssetRefKey } from '@subwallet/extension-base/services/chain-service/utils'; import { BaseSwapStepMetadata, CommonStepDetail, CommonStepType, DynamicSwapAction, DynamicSwapType, SwapStepType } from '@subwallet/extension-base/types'; import { SwapPair, SwapProviderId } from '@subwallet/extension-base/types/swap'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import BigN from 'bignumber.js'; +const swapUtilsLogger = createLogger('SwapUtils'); + export const CHAIN_FLIP_TESTNET_EXPLORER = 'https://blocks-perseverance.chainflip.io'; export const CHAIN_FLIP_MAINNET_EXPLORER = 'https://scan.chainflip.io'; @@ -59,7 +62,7 @@ export function getChainRouteFromSteps (steps: CommonStepDetail[]): string[] { const metadata = currentStep.metadata as unknown as BaseSwapStepMetadata; if (!metadata) { - console.error('Step has no metadata'); + swapUtilsLogger.error('Step has no metadata'); return chainRoute; } diff --git a/packages/extension-base/src/services/transaction-service/index.ts b/packages/extension-base/src/services/transaction-service/index.ts index 566135df0e1..31d476459c7 100644 --- a/packages/extension-base/src/services/transaction-service/index.ts +++ b/packages/extension-base/src/services/transaction-service/index.ts @@ -42,6 +42,9 @@ import { EventRecord } from '@polkadot/types/interfaces'; import { SignerPayloadJSON } from '@polkadot/types/types/extrinsic'; import { hexToU8a, isHex } from '@polkadot/util'; import { HexString } from '@polkadot/util/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const transactionServiceLogger = createLogger('TransactionService'); import { GovVoteType } from '../open-gov/interface'; @@ -1194,14 +1197,14 @@ export default class TransactionService { return [historyItem, receiverHistory]; } } catch (e) { - console.warn(e); + transactionServiceLogger.warn('Error processing transaction history', e); } return [historyItem]; } private onSigned ({ id }: TransactionEventResponse) { - console.debug(`Transaction "${id}" is signed`); + transactionServiceLogger.debug(`Transaction "${id}" is signed`); } private onSend ({ id, nonce, startBlock }: TransactionEventResponse) { @@ -1209,11 +1212,11 @@ export default class TransactionService { this.updateTransaction(id, { status: ExtrinsicStatus.SUBMITTING }); // Create Input History Transaction History - this.state.historyService.insertHistories(this.transactionToHistories(id, startBlock, nonce)).catch(console.error); + this.state.historyService.insertHistories(this.transactionToHistories(id, startBlock, nonce)).catch((error) => transactionServiceLogger.error('Error inserting transaction histories', error)); - this.createProcessNotification(id).catch(console.error); + this.createProcessNotification(id).catch((error) => transactionServiceLogger.error('Error creating process notification', error)); - console.debug(`Transaction "${id}" is sent`); + transactionServiceLogger.debug(`Transaction "${id}" is sent`); } private onHasTransactionHash ({ blockHash, extrinsicHash, id }: TransactionEventResponse) { @@ -1223,9 +1226,9 @@ export default class TransactionService { this.updateTransaction(id, updateData); // In this case transaction id is the same as extrinsic hash and will change after below update - this.state.historyService.updateHistoryByExtrinsicHash(id, updateData).catch(console.error); + this.state.historyService.updateHistoryByExtrinsicHash(id, updateData).catch((error) => transactionServiceLogger.error('Error updating history by extrinsic hash', error)); - console.debug(`Transaction "${id}" is submitted with hash ${extrinsicHash || ''}`); + transactionServiceLogger.debug(`Transaction "${id}" is submitted with hash ${extrinsicHash || ''}`); const transaction = this.getTransaction(id); @@ -1252,18 +1255,18 @@ export default class TransactionService { const sender = keyring.getPair(inputData.from); balanceService.refreshBalanceForAddress(sender.address, transaction.chain, inputData.tokenSlug, transaction.extrinsicType) - .catch((error) => console.error('Failed to run balance subscription:', error)); + .catch((error) => transactionServiceLogger.error('Failed to run balance subscription', error)); } catch (e) { - console.error(e); + transactionServiceLogger.error('Error refreshing sender balance', e); } try { const recipient = keyring.getPair(inputData.to); balanceService.refreshBalanceForAddress(recipient.address, transaction.chain, inputData.tokenSlug, transaction.extrinsicType) - .catch((error) => console.error('Failed to run balance subscription:', error)); + .catch((error) => transactionServiceLogger.error('Failed to run balance subscription', error)); } catch (e) { - console.error(e); + transactionServiceLogger.error('Error refreshing recipient balance', e); } } } @@ -1281,18 +1284,18 @@ export default class TransactionService { .then(() => { this.state.eventService.emit('transaction.transferNft', undefined); }) - .catch(console.error); + .catch((error) => transactionServiceLogger.error('Error handling NFT transfer', error)); } catch (e) { - console.error(e); + transactionServiceLogger.error('Error processing NFT transfer for sender', e); } try { const recipient = keyring.getPair(inputData.recipientAddress); recipient && this.state.dbService.addNft(recipient.address, { ...inputData.nftItem, owner: recipient.address }) - .catch(console.error); + .catch((error) => transactionServiceLogger.error('Error adding NFT for recipient', error)); } catch (e) { - console.error(e); + transactionServiceLogger.error('Error processing NFT transfer for recipient', e); } } else if ([ExtrinsicType.STAKING_BOND, ExtrinsicType.STAKING_UNBOND, ExtrinsicType.STAKING_WITHDRAW, ExtrinsicType.STAKING_CANCEL_UNSTAKE, ExtrinsicType.STAKING_CLAIM_REWARD, ExtrinsicType.JOIN_YIELD_POOL, ExtrinsicType.STAKING_LEAVE_POOL].includes(transaction.extrinsicType)) { this.state.eventService.emit('transaction.submitStaking', transaction.chain); @@ -1301,7 +1304,7 @@ export default class TransactionService { const toAssetSlug = inputData.quote.pair.to; // todo: consider async - this.state.chainService.updateAssetSetting(toAssetSlug, { visible: true }, true).catch(console.error); + this.state.chainService.updateAssetSetting(toAssetSlug, { visible: true }, true).catch((error) => transactionServiceLogger.error('Error updating asset setting', error)); } } @@ -1317,7 +1320,7 @@ export default class TransactionService { blockNumber: blockNumber || 0, blockHash: blockHash || '', blockTime - }).catch(console.error); + }).catch((error) => transactionServiceLogger.error('Error updating history on success', error)); const info = isHex(extrinsicHash) ? extrinsicHash : getBaseTransactionInfo(transaction, this.state.chainService.getChainInfoMap()); @@ -1345,7 +1348,7 @@ export default class TransactionService { status: nextStatus, blockNumber: blockNumber || 0, blockHash: blockHash || '' - }).catch(console.error); + }).catch((error) => transactionServiceLogger.error('Error updating history on failure', error)); const info = isHex(transaction?.extrinsicHash) ? transaction?.extrinsicHash : getBaseTransactionInfo(transaction, this.state.chainService.getChainInfoMap()); @@ -1373,7 +1376,7 @@ export default class TransactionService { status: nextStatus, blockNumber: blockNumber || 0, blockHash: blockHash || '' - }).catch(console.error); + }).catch((error) => transactionServiceLogger.error('Error updating history on failure', error)); const info = isHex(transaction?.extrinsicHash) ? transaction?.extrinsicHash : getBaseTransactionInfo(transaction, this.state.chainService.getChainInfoMap()); @@ -1448,7 +1451,7 @@ export default class TransactionService { : '' : payload.data || ''; } catch (e) { - console.warn('Unable to parse contract input data'); + transactionServiceLogger.warn('Unable to parse contract input data'); payload.parseData = payload.data as string; } } @@ -2084,7 +2087,7 @@ export default class TransactionService { }); event.on('success', (transactionStatus) => { - console.log(transactionStatus); + transactionServiceLogger.debug('Transaction success', transactionStatus); eventData.blockHash = transactionStatus.block_hash || undefined; eventData.blockNumber = transactionStatus.block_height || undefined; eventData.blockTime = transactionStatus.block_time ? (transactionStatus.block_time * 1000) : undefined; @@ -2226,7 +2229,7 @@ export default class TransactionService { network: transaction.chain, extrinsicHash: transaction.extrinsicHash }) - .catch(console.error); + .catch((error) => transactionServiceLogger.error('Error creating transaction notification', error)); } public async createProcessIfNeed (process: ProcessTransactionData) { @@ -2246,7 +2249,7 @@ export default class TransactionService { const { processId } = step; this.aliveProcessMap.delete(processId); - this.state.dbService.deleteProcessTransactionById(processId).catch(console.error); + this.state.dbService.deleteProcessTransactionById(processId).catch((error) => transactionServiceLogger.error('Error deleting process transaction', error)); this.updateAliveProcess(); } @@ -2302,7 +2305,7 @@ export default class TransactionService { } this.aliveProcessMap.set(processId, process); - this.state.dbService.upsertProcessTransaction(process).catch(console.error); + this.state.dbService.upsertProcessTransaction(process).catch((error) => transactionServiceLogger.error('Error upserting process transaction', error)); if ([StepStatus.COMPLETE, StepStatus.FAILED, StepStatus.TIMEOUT].includes(process.status)) { this.aliveProcessMap.delete(processId); @@ -2324,11 +2327,11 @@ export default class TransactionService { process.status = data.status; } - this.state.dbService.upsertProcessTransaction(process).catch(console.error); + this.state.dbService.upsertProcessTransaction(process).catch((error) => transactionServiceLogger.error('Error upserting process transaction', error)); } } }) - .catch(console.error); + .catch((error) => transactionServiceLogger.error('Error getting process transaction by id', error)); } } diff --git a/packages/extension-base/src/services/wallet-connect-service/handler/Eip155RequestHandler.ts b/packages/extension-base/src/services/wallet-connect-service/handler/Eip155RequestHandler.ts index c97278be8f8..deaeba22891 100644 --- a/packages/extension-base/src/services/wallet-connect-service/handler/Eip155RequestHandler.ts +++ b/packages/extension-base/src/services/wallet-connect-service/handler/Eip155RequestHandler.ts @@ -6,9 +6,12 @@ import KoniState from '@subwallet/extension-base/koni/background/handlers/State' import WalletConnectService from '@subwallet/extension-base/services/wallet-connect-service'; import { getWCId, parseRequestParams } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; import { EIP155_SIGNING_METHODS } from '@subwallet/extension-base/services/wallet-connect-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { SignClientTypes } from '@walletconnect/types'; import { getSdkError } from '@walletconnect/utils'; +const eip155RequestHandlerLogger = createLogger('Eip155RequestHandler'); + export default class Eip155RequestHandler { readonly #walletConnectService: WalletConnectService; readonly #koniState: KoniState; @@ -19,7 +22,7 @@ export default class Eip155RequestHandler { } #handleError (topic: string, id: number, e: unknown) { - console.log(e); + eip155RequestHandlerLogger.debug('Error in EIP155 request handler', e); let message = (e as Error).message; if (message.includes('User Rejected Request')) { @@ -29,7 +32,7 @@ export default class Eip155RequestHandler { this.#walletConnectService.responseRequest({ topic: topic, response: formatJsonRpcError(id, message) - }).catch(console.error); + }).catch((error) => eip155RequestHandlerLogger.error('Error responding to wallet connect request', error)); } public handleRequest (requestEvent: SignClientTypes.EventArguments['session_request']) { diff --git a/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts b/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts index de0e5343abe..1ff0c5dbf6f 100644 --- a/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts +++ b/packages/extension-base/src/services/wallet-connect-service/handler/PolkadotRequestHandler.ts @@ -8,11 +8,14 @@ import RequestService from '@subwallet/extension-base/services/request-service'; import WalletConnectService from '@subwallet/extension-base/services/wallet-connect-service'; import { getWCId, parseRequestParams } from '@subwallet/extension-base/services/wallet-connect-service/helpers'; import { POLKADOT_SIGNING_METHODS } from '@subwallet/extension-base/services/wallet-connect-service/types'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isSameAddress } from '@subwallet/extension-base/utils'; import keyring from '@subwallet/ui-keyring'; import { SignClientTypes } from '@walletconnect/types'; import { getSdkError } from '@walletconnect/utils'; +const polkadotRequestHandlerLogger = createLogger('PolkadotRequestHandler'); + export default class PolkadotRequestHandler { readonly #walletConnectService: WalletConnectService; readonly #requestService: RequestService; @@ -38,7 +41,7 @@ export default class PolkadotRequestHandler { this.#walletConnectService.responseRequest({ topic: topic, response: formatJsonRpcError(id, message) - }).catch(console.error); + }).catch((error) => polkadotRequestHandlerLogger.error('Error responding to wallet connect request', error)); } public handleRequest (requestEvent: SignClientTypes.EventArguments['session_request']) { diff --git a/packages/extension-base/src/services/wallet-connect-service/index.ts b/packages/extension-base/src/services/wallet-connect-service/index.ts index 048cd9b5429..b48f16d2794 100644 --- a/packages/extension-base/src/services/wallet-connect-service/index.ts +++ b/packages/extension-base/src/services/wallet-connect-service/index.ts @@ -7,8 +7,11 @@ import RequestService from '@subwallet/extension-base/services/request-service'; import Eip155RequestHandler from '@subwallet/extension-base/services/wallet-connect-service/handler/Eip155RequestHandler'; import { SWStorage } from '@subwallet/extension-base/storage'; import { wait } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { IKeyValueStorage } from '@walletconnect/keyvaluestorage'; import SignClient from '@walletconnect/sign-client'; + +const walletConnectLogger = createLogger('WalletConnectService'); import { EngineTypes, SessionTypes, SignClientTypes } from '@walletconnect/types'; import { getInternalError, getSdkError } from '@walletconnect/utils'; import { BehaviorSubject } from 'rxjs'; @@ -67,7 +70,7 @@ export default class WalletConnectService { this.#polkadotRequestHandler = new PolkadotRequestHandler(this, requestService); this.#eip155RequestHandler = new Eip155RequestHandler(this.#koniState, this); - this.initClient().catch(console.error); + this.initClient().catch((error) => walletConnectLogger.error('Error initializing WalletConnect client', error)); } private async haveData () { @@ -171,7 +174,7 @@ export default class WalletConnectService { throw Error(getSdkError('INVALID_METHOD').message + ' ' + method); } } catch (e) { - console.log(e); + walletConnectLogger.error('Error in WalletConnect handler', e); try { const requestSession = this.getSession(topic); @@ -183,7 +186,7 @@ export default class WalletConnectService { this.responseRequest({ topic: topic, response: formatJsonRpcError(id, (e as Error).message) - }).catch(console.error); + }).catch((error) => walletConnectLogger.error('Error handling WalletConnect request', error)); } } @@ -200,7 +203,7 @@ export default class WalletConnectService { await this.#client.ping({ topic }); } } catch (e) { - console.error(e); + walletConnectLogger.error('Error pinging WalletConnect session', e); } } @@ -208,8 +211,8 @@ export default class WalletConnectService { this.#client?.on('session_proposal', this.#onSessionProposal.bind(this)); this.#client?.on('session_request', this.#onSessionRequest.bind(this)); this.#client?.on('session_ping', this.#onPingReply.bind(this)); - this.#client?.on('session_event', (data) => console.log('event', data)); - this.#client?.on('session_update', (data) => console.log('update', data)); + this.#client?.on('session_event', (data) => walletConnectLogger.debug('WalletConnect session event', data)); + this.#client?.on('session_update', (data) => walletConnectLogger.debug('WalletConnect session update', data)); this.#client?.on('session_delete', this.#updateSessions.bind(this)); } @@ -302,7 +305,7 @@ export default class WalletConnectService { reason: getSdkError('USER_DISCONNECTED') }); } catch (e) { - console.error(e); + walletConnectLogger.error('Error in WalletConnect operation', e); } } @@ -316,7 +319,7 @@ export default class WalletConnectService { reason: getSdkError('USER_DISCONNECTED') }); } catch (e) { - console.error(e); + walletConnectLogger.error('Error in WalletConnect operation', e); } } @@ -328,7 +331,7 @@ export default class WalletConnectService { try { await this.#client?.core.storage.removeItem(key); } catch (e) { - console.error(e); + walletConnectLogger.error('Error in WalletConnect operation', e); } } diff --git a/packages/extension-base/src/storage/index.ts b/packages/extension-base/src/storage/index.ts index cba573b6088..e4dbf367e89 100644 --- a/packages/extension-base/src/storage/index.ts +++ b/packages/extension-base/src/storage/index.ts @@ -3,9 +3,12 @@ import KoniDatabase from '@subwallet/extension-base/services/storage-service/databases'; import { createPromiseHandler } from '@subwallet/extension-base/utils/promise'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { xglobal } from '@polkadot/x-global'; +const swStorageLogger = createLogger('SWStorage'); + const hasLocalStorage = typeof localStorage !== 'undefined'; // Create localStorage adaptor @@ -26,7 +29,7 @@ export class SWStorage { this.isReady = true; this.waitReadyHandler.resolve(this); }) - .catch(console.error); + .catch((e) => swStorageLogger.error('Error initializing SWStorage', e)); } async setItem (key: string, value: string) { @@ -36,7 +39,7 @@ export class SWStorage { if (this.localStorage) { this.localStorage?.setItem(key, value); } else { - this.kvDatabase.put({ key, value }).catch(console.error); + this.kvDatabase.put({ key, value }).catch((e) => swStorageLogger.error('Error putting item to kvDatabase', e)); } } @@ -59,7 +62,7 @@ export class SWStorage { this.kvDatabase .bulkPut(putList) - .catch(console.error); + .catch((e) => swStorageLogger.error('Error bulk putting items to kvDatabase', e)); } } @@ -95,7 +98,7 @@ export class SWStorage { this.kvDatabase .where({ key }) .delete() - .catch(console.error); + .catch((e) => swStorageLogger.error('Error deleting item from kvDatabase', e)); } } @@ -114,7 +117,7 @@ export class SWStorage { .where('key') .anyOf(keys) .delete() - .catch(console.error); + .catch((e) => swStorageLogger.error('Error deleting items from kvDatabase', e)); } } @@ -125,7 +128,7 @@ export class SWStorage { if (this.localStorage) { this.localStorage.clear(); } else { - this.kvDatabase.clear().catch(console.error); + this.kvDatabase.clear().catch((e) => swStorageLogger.error('Error clearing kvDatabase', e)); } } diff --git a/packages/extension-base/src/stores/Base.ts b/packages/extension-base/src/stores/Base.ts index 59783b79325..4917552fb2e 100644 --- a/packages/extension-base/src/stores/Base.ts +++ b/packages/extension-base/src/stores/Base.ts @@ -1,13 +1,17 @@ // Copyright 2019-2022 @polkadot/extension-base authors & contributors // SPDX-License-Identifier: Apache-2.0 +import { createLogger } from '@subwallet/extension-base/utils/logger'; + type StoreValue = Record; +const baseStoreLogger = createLogger('BaseStore'); + const lastError = (type: string): void => { const error = chrome.runtime.lastError; if (error) { - console.error(`BaseStore.${type}:: runtime.lastError:`, error); + baseStoreLogger.error(`BaseStore.${type}:: runtime.lastError`, error); } }; diff --git a/packages/extension-base/src/stores/Keyring.ts b/packages/extension-base/src/stores/Keyring.ts index d4ca29c61f6..7fcabf05df3 100644 --- a/packages/extension-base/src/stores/Keyring.ts +++ b/packages/extension-base/src/stores/Keyring.ts @@ -6,13 +6,17 @@ import type { PasswordStore } from '@subwallet/ui-keyring/types'; import { SUBWALLET_KEYRING } from '@subwallet/ui-keyring/defaults'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + type StoreValue = Record; +const keyringStoreLogger = createLogger('KeyringStore'); + const lastError = (type: string): void => { const error = chrome.runtime.lastError; if (error) { - console.error(`KeyringStore.${type}:: runtime.lastError:`, error); + keyringStoreLogger.error(`KeyringStore.${type}:: runtime.lastError`, error); } }; diff --git a/packages/extension-base/src/stores/TransactionHistory.ts b/packages/extension-base/src/stores/TransactionHistory.ts index 6e3c103b6da..67b9235b847 100644 --- a/packages/extension-base/src/stores/TransactionHistory.ts +++ b/packages/extension-base/src/stores/TransactionHistory.ts @@ -4,12 +4,15 @@ import { TxHistoryItem } from '@subwallet/extension-base/background/KoniTypes'; import { EXTENSION_PREFIX } from '@subwallet/extension-base/defaults'; import SubscribableStore from '@subwallet/extension-base/stores/SubscribableStore'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const transactionHistoryStoreLogger = createLogger('TransactionHistoryStore'); const lastError = (type: string): void => { const error = chrome.runtime.lastError; if (error) { - console.error(`TransactionHistoryStore.${type}:: runtime.lastError:`, error); + transactionHistoryStoreLogger.error(`TransactionHistoryStore.${type}:: runtime.lastError`, error); } }; diff --git a/packages/extension-base/src/strategy/api-request-strategy-v2/index.ts b/packages/extension-base/src/strategy/api-request-strategy-v2/index.ts index 9f42a1c002c..7def33d2a7c 100644 --- a/packages/extension-base/src/strategy/api-request-strategy-v2/index.ts +++ b/packages/extension-base/src/strategy/api-request-strategy-v2/index.ts @@ -3,9 +3,12 @@ import { SWError } from '@subwallet/extension-base/background/errors/SWError'; import { BASE_MINUTE_INTERVAL } from '@subwallet/extension-base/constants'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { Md5 } from 'ts-md5'; import { ApiRequestContext } from '../api-request-strategy/types'; + +const apiRequestStrategyLogger = createLogger('ApiRequestStrategyV2'); import { ApiRequestStrategyV2, ApiRequestV2 } from './types'; export abstract class BaseApiRequestStrategyV2 implements ApiRequestStrategyV2 { @@ -79,7 +82,7 @@ export abstract class BaseApiRequestStrategyV2 implements ApiRequestStrategyV2 { return; } - console.log('[ApiRequestStrategyV2] Processing requests...', remainingRequests.map((r) => r.groupId)); + apiRequestStrategyLogger.debug('Processing requests', remainingRequests.map((r) => r.groupId)); // Get first this.limit requests base on id const requests = remainingRequests @@ -98,7 +101,7 @@ export abstract class BaseApiRequestStrategyV2 implements ApiRequestStrategyV2 { request.resolve(resp); - console.log('[ApiRequestStrategyV2] Cache hit for request', request.id, 'with cache key', request.cacheKey); + apiRequestStrategyLogger.debug(`Cache hit for request ${request.id} with cache key ${request.cacheKey}`); delete this.requestMap[request.id]; diff --git a/packages/extension-base/src/utils/eth/parseTransaction/base.ts b/packages/extension-base/src/utils/eth/parseTransaction/base.ts index 2b2aa1d80cd..0bca84a032e 100644 --- a/packages/extension-base/src/utils/eth/parseTransaction/base.ts +++ b/packages/extension-base/src/utils/eth/parseTransaction/base.ts @@ -9,6 +9,10 @@ import isBuffer from 'is-buffer'; // @ts-ignore import { _jsonInterfaceMethodToString, AbiInput, AbiItem, keccak256 } from 'web3-utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const parseTransactionLogger = createLogger('ParseTransaction'); + export interface InputData { method: string | null; methodName: string | null; @@ -275,7 +279,7 @@ export class InputDataDecoder { }; } } catch (err) { - console.log(err); + parseTransactionLogger.error('Error parsing transaction', err); } } diff --git a/packages/extension-base/src/utils/fee/transfer.ts b/packages/extension-base/src/utils/fee/transfer.ts index 9e2d20e062f..48e56bd0c74 100644 --- a/packages/extension-base/src/utils/fee/transfer.ts +++ b/packages/extension-base/src/utils/fee/transfer.ts @@ -26,8 +26,11 @@ import { ValidateTransactionResponseInput } from '@subwallet/extension-base/serv import { EvmEIP1559FeeDetail, EvmEIP1559FeeOption, FeeChainType, FeeDetail, FeeInfo, SubstrateTipInfo, TransactionFee } from '@subwallet/extension-base/types'; import { ResponseSubscribeTransfer } from '@subwallet/extension-base/types/balance/transfer'; import { BN_ZERO } from '@subwallet/extension-base/utils'; +import { createLogger } from '@subwallet/extension-base/utils/logger'; import { isCardanoAddress, isTonAddress } from '@subwallet/keyring'; import { isBitcoinAddress } from '@subwallet/keyring/utils/address/validate'; + +const feeTransferLogger = createLogger('FeeTransfer'); import BigN from 'bignumber.js'; import * as bitcoin from 'bitcoinjs-lib'; import { TransactionConfig } from 'web3-core'; @@ -320,7 +323,7 @@ export const calculateTransferMaxTransferable = async (id: string, request: Calc error = (e as Error).message || 'Unable to estimate fee'; - console.warn('Unable to estimate fee', e); + feeTransferLogger.warn('Unable to estimate fee', e); } if (isTransferLocalTokenAndPayThatTokenAsFee && feeChainType === 'substrate') { @@ -518,7 +521,7 @@ export const calculateXcmMaxTransferable = async (id: string, request: Calculate error = (e as Error).message || 'Unable to estimate fee'; - console.warn('Unable to estimate fee', e); + feeTransferLogger.warn('Unable to estimate fee', e); } if (!destToken) { diff --git a/packages/extension-base/src/utils/index.ts b/packages/extension-base/src/utils/index.ts index ac0a7a0fa24..8c2df7d231d 100644 --- a/packages/extension-base/src/utils/index.ts +++ b/packages/extension-base/src/utils/index.ts @@ -440,3 +440,4 @@ export * from './swap'; export * from './translate'; export * from './bitcoin'; export * from './setup-api-sdk'; +export * from './logger'; \ No newline at end of file diff --git a/packages/extension-base/src/utils/logger/Logger.ts b/packages/extension-base/src/utils/logger/Logger.ts new file mode 100644 index 00000000000..1b19121d38b --- /dev/null +++ b/packages/extension-base/src/utils/logger/Logger.ts @@ -0,0 +1,298 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import log from 'loglevel'; +import { LogContext, LogLevel, LoggerConfig, StructuredLogData } from './types'; +import { sentryAdapter } from './sentry-adapter'; + +const LOG_LEVELS: Record = { + trace: 0, + debug: 1, + info: 2, + warn: 3, + error: 4 +}; + +const isDevelopment = process.env.NODE_ENV !== 'production'; + +/** + * Extract context from Error stack trace + */ +function extractContext (skipFrames = 2): LogContext | null { + try { + const stack = new Error().stack; + if (!stack) { + return null; + } + + const lines = stack.split('\n'); + // Skip Error constructor and extractContext call + const frame = lines[skipFrames + 1]; + + if (!frame) { + return null; + } + + // Match patterns like: "at functionName (file://path/to/file.ts:123:45)" + const match = frame.match(/at\s+(?:async\s+)?(.+?)\s+\((.+?):(\d+):(\d+)\)/); + + if (match) { + const [, functionName, filePath, line, column] = match; + const fileName = filePath.split('/').pop() || filePath; + + return { + file: fileName, + function: functionName, + line: parseInt(line, 10), + column: parseInt(column, 10), + timestamp: new Date().toISOString(), + level: 'info' as LogLevel, + loggerName: '' + }; + } + } catch { + // Ignore errors in context extraction + } + + return null; +} + +export class Logger { + private logInstance: log.Logger; + private name: string; + private config: Required; + private groupStack: string[] = []; + + constructor (config: LoggerConfig) { + this.name = config.name; + this.config = { + name: config.name, + level: config.level || (isDevelopment ? 'debug' : 'info'), + enableStructuredLogging: config.enableStructuredLogging ?? false, + enableContextCapture: config.enableContextCapture ?? true + }; + + // Create a named logger instance + this.logInstance = log.getLogger(this.name); + this.logInstance.setLevel(this.getLogLevelNumber(this.config.level) as log.LogLevelDesc); + } + + private getLogLevelNumber (level: LogLevel): number { + return LOG_LEVELS[level]; + } + + private shouldLog (level: LogLevel): boolean { + return LOG_LEVELS[level] >= this.getLogLevelNumber(this.config.level); + } + + private formatMessage (level: LogLevel, message: string, ...args: unknown[]): string { + const prefix = `[${this.name}] [${level.toUpperCase()}]`; + return `${prefix} ${message}`; + } + + private createLogContext (level: LogLevel): LogContext { + const baseContext: LogContext = { + timestamp: new Date().toISOString(), + level, + loggerName: this.name + }; + + if (this.config.enableContextCapture) { + const extracted = extractContext(3); + if (extracted) { + return { ...baseContext, ...extracted }; + } + } + + return baseContext; + } + + private logStructured (level: LogLevel, data: StructuredLogData): void { + if (!this.shouldLog(level)) { + return; + } + + const context = this.createLogContext(level); + const logEntry = { + ...context, + message: data.message, + context: data.context, + error: data.error instanceof Error ? { + name: data.error.name, + message: data.error.message, + stack: data.error.stack + } : data.error, + tags: data.tags, + extra: data.extra + }; + + // Output structured JSON + const jsonOutput = JSON.stringify(logEntry, null, 2); + this.logInstance[level](jsonOutput); + + // Add breadcrumb to Sentry + if (data.error instanceof Error) { + sentryAdapter.captureException(data.error, { + ...data.context, + logger: this.name, + tags: data.tags + }); + } else { + sentryAdapter.addBreadcrumb(data.message, level, { + ...data.context, + logger: this.name, + tags: data.tags + }); + } + } + + // Simple logging methods (drop-in console replacement) + error (message: string, ...args: unknown[]): void { + if (!this.shouldLog('error')) { + return; + } + + const formatted = this.formatMessage('error', message); + this.logInstance.error(formatted, ...args); + + // Add breadcrumb for errors + if (args.length > 0 && args[0] instanceof Error) { + sentryAdapter.captureException(args[0] as Error, { + message, + logger: this.name + }); + } else { + sentryAdapter.addBreadcrumb(message, 'error', { + logger: this.name, + args: args.length > 0 ? args : undefined + }); + } + } + + warn (message: string, ...args: unknown[]): void { + if (!this.shouldLog('warn')) { + return; + } + + const formatted = this.formatMessage('warn', message); + this.logInstance.warn(formatted, ...args); + sentryAdapter.addBreadcrumb(message, 'warn', { + logger: this.name, + args: args.length > 0 ? args : undefined + }); + } + + info (message: string, ...args: unknown[]): void { + if (!this.shouldLog('info')) { + return; + } + + const formatted = this.formatMessage('info', message); + this.logInstance.info(formatted, ...args); + sentryAdapter.addBreadcrumb(message, 'info', { + logger: this.name, + args: args.length > 0 ? args : undefined + }); + } + + log (message: string, ...args: unknown[]): void { + this.info(message, ...args); + } + + debug (message: string, ...args: unknown[]): void { + if (!this.shouldLog('debug')) { + return; + } + + const formatted = this.formatMessage('debug', message); + this.logInstance.debug(formatted, ...args); + sentryAdapter.addBreadcrumb(message, 'debug', { + logger: this.name, + args: args.length > 0 ? args : undefined + }); + } + + trace (message: string, ...args: unknown[]): void { + if (!this.shouldLog('trace')) { + return; + } + + const formatted = this.formatMessage('trace', message); + this.logInstance.trace(formatted, ...args); + sentryAdapter.addBreadcrumb(message, 'trace', { + logger: this.name, + args: args.length > 0 ? args : undefined + }); + } + + // Structured logging methods + errorStructured (data: StructuredLogData): void { + this.logStructured('error', data); + } + + warnStructured (data: StructuredLogData): void { + this.logStructured('warn', data); + } + + infoStructured (data: StructuredLogData): void { + this.logStructured('info', data); + } + + debugStructured (data: StructuredLogData): void { + this.logStructured('debug', data); + } + + traceStructured (data: StructuredLogData): void { + this.logStructured('trace', data); + } + + // Public alias for backward compatibility (calls infoStructured) + logStructuredPublic (data: StructuredLogData): void { + this.infoStructured(data); + } + + // Group methods (console.group/groupEnd replacement) + group (label?: string): void { + const groupLabel = label || `Group ${this.groupStack.length + 1}`; + this.groupStack.push(groupLabel); + + if (this.shouldLog('debug')) { + const indent = ' '.repeat(this.groupStack.length - 1); + const formatted = this.formatMessage('debug', `${indent}▼ ${groupLabel}`); + this.logInstance.debug(formatted); + } + } + + groupEnd (): void { + if (this.groupStack.length === 0) { + return; + } + + const groupLabel = this.groupStack.pop()!; + + if (this.shouldLog('debug')) { + const indent = ' '.repeat(this.groupStack.length); + const formatted = this.formatMessage('debug', `${indent}▲ ${groupLabel}`); + this.logInstance.debug(formatted); + } + } + + // Utility methods + setLevel (level: LogLevel): void { + this.config.level = level; + this.logInstance.setLevel(this.getLogLevelNumber(level) as log.LogLevelDesc); + } + + getLevel (): LogLevel { + return this.config.level; + } + + getName (): string { + return this.name; + } + + // Polkadot compatibility - noop method + noop (...values: unknown[]): void { + // No operation - required by Polkadot Logger interface + } +} diff --git a/packages/extension-base/src/utils/logger/index.ts b/packages/extension-base/src/utils/logger/index.ts new file mode 100644 index 00000000000..ee2466644d3 --- /dev/null +++ b/packages/extension-base/src/utils/logger/index.ts @@ -0,0 +1,32 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { Logger } from './Logger'; +import { LoggerConfig } from './types'; + +/** + * Create a named logger instance + * @param name - Logger name (typically the class or module name) + * @param config - Optional logger configuration + * @returns Logger instance + */ +export function createLogger (name: string, config?: Partial): Logger { + return new Logger({ + name, + ...config + }); +} + +/** + * Default logger instance + */ +export const defaultLogger = createLogger('SubWallet'); + +// Export types +export type { LogLevel, LoggerConfig, LogContext, StructuredLogData, SentryAdapter } from './types'; + +// Export Logger class for advanced usage +export { Logger } from './Logger'; + +// Export Sentry adapter for future integration +export { sentryAdapter } from './sentry-adapter'; diff --git a/packages/extension-base/src/utils/logger/sentry-adapter.ts b/packages/extension-base/src/utils/logger/sentry-adapter.ts new file mode 100644 index 00000000000..82941a2abb6 --- /dev/null +++ b/packages/extension-base/src/utils/logger/sentry-adapter.ts @@ -0,0 +1,28 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { LogLevel, SentryAdapter } from './types'; + +/** + * Placeholder Sentry adapter for future integration + * Currently implements no-op methods + * When Sentry SDK is integrated, replace these with actual Sentry calls + */ +class SentryAdapterImpl implements SentryAdapter { + captureException (error: Error, context?: Record): void { + // TODO: Integrate Sentry SDK + // Example: Sentry.captureException(error, { extra: context }); + } + + addBreadcrumb (message: string, level: LogLevel, data?: Record): void { + // TODO: Integrate Sentry SDK + // Example: Sentry.addBreadcrumb({ message, level, data }); + } + + setContext (key: string, context: Record): void { + // TODO: Integrate Sentry SDK + // Example: Sentry.setContext(key, context); + } +} + +export const sentryAdapter = new SentryAdapterImpl(); diff --git a/packages/extension-base/src/utils/logger/types.ts b/packages/extension-base/src/utils/logger/types.ts new file mode 100644 index 00000000000..3b21139876f --- /dev/null +++ b/packages/extension-base/src/utils/logger/types.ts @@ -0,0 +1,35 @@ +// Copyright 2019-2022 @subwallet/extension-base authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace'; + +export interface LoggerConfig { + name: string; + level?: LogLevel; + enableStructuredLogging?: boolean; + enableContextCapture?: boolean; +} + +export interface LogContext { + file?: string; + function?: string; + line?: number; + column?: number; + timestamp: string; + level: LogLevel; + loggerName: string; +} + +export interface StructuredLogData { + message: string; + context?: Record; + error?: Error | unknown; + tags?: string[]; + extra?: Record; +} + +export interface SentryAdapter { + captureException(error: Error, context?: Record): void; + addBreadcrumb(message: string, level: LogLevel, data?: Record): void; + setContext(key: string, context: Record): void; +} diff --git a/packages/extension-base/src/utils/metadata.ts b/packages/extension-base/src/utils/metadata.ts index 05e5555936f..686fe356841 100644 --- a/packages/extension-base/src/utils/metadata.ts +++ b/packages/extension-base/src/utils/metadata.ts @@ -8,6 +8,10 @@ import { ApiPromise } from '@polkadot/api'; import { TypeRegistry } from '@polkadot/types'; import { getSpecExtensions, getSpecTypes } from '@polkadot/types-known'; import { formatBalance, isNumber, u8aToHex } from '@polkadot/util'; + +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const metadataUtilsLogger = createLogger('MetadataUtils'); import { HexString } from '@polkadot/util/types'; import { defaults as addressDefaults } from '@polkadot/util-crypto/address/defaults'; import { ExtraInfo, merkleizeMetadata } from '@polkadot-api/merkleize-metadata'; @@ -64,11 +68,11 @@ const updateMetadataV15 = async (chain: string, api: ApiPromise, chainService?: hexV15 }; - chainService?.upsertMetadataV15(chain, { ...updateMetadata }).catch(console.error); + chainService?.upsertMetadataV15(chain, { ...updateMetadata }).catch((e) => metadataUtilsLogger.error('Error upserting metadata V15', e)); } } } catch (err) { - console.error('Error:', err); + metadataUtilsLogger.error('Error in updateMetadataV15', err); } }; @@ -110,7 +114,7 @@ const updateMetadata = async ( tokenInfo }; - chainService?.upsertMetadata(chain, { ...updateMetadata }).catch(console.error); + chainService?.upsertMetadata(chain, { ...updateMetadata }).catch((e) => metadataUtilsLogger.error('Error upserting metadata', e)); }; export const cacheMetadata = ( @@ -120,7 +124,7 @@ export const cacheMetadata = ( ): void => { // Update metadata to database with async methods substrateApi.api.isReady.then((api) => { - updateMetadata(chain, api, chainService).catch(console.error); - updateMetadataV15(chain, api, chainService).catch(console.error); - }).catch(console.error); + updateMetadata(chain, api, chainService).catch((e) => metadataUtilsLogger.error('Error updating metadata', e)); + updateMetadataV15(chain, api, chainService).catch((e) => metadataUtilsLogger.error('Error updating metadata V15', e)); + }).catch((e) => metadataUtilsLogger.error('Error in cacheMetadata', e)); }; diff --git a/packages/extension-base/src/utils/promise.ts b/packages/extension-base/src/utils/promise.ts index b56d5ae0c10..6249f5240e8 100644 --- a/packages/extension-base/src/utils/promise.ts +++ b/packages/extension-base/src/utils/promise.ts @@ -1,13 +1,17 @@ // Copyright 2019-2022 @subwallet/extension-base // SPDX-License-Identifier: Apache-2.0 +import { createLogger } from '@subwallet/extension-base/utils/logger'; + +const promiseUtilsLogger = createLogger('PromiseUtils'); + export function createPromiseHandler () { let _resolve: (value: T) => void = () => { - console.warn('This promise handler is not implemented'); + promiseUtilsLogger.warn('This promise handler is not implemented'); }; let _reject: (reason?: unknown) => void = () => { - console.warn('This promise handler is not implemented'); + promiseUtilsLogger.warn('This promise handler is not implemented'); }; const promise = new Promise((resolve, reject) => {