├── .editorconfig ├── .env.example ├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── codeql-analysis.yml │ ├── create_release.yaml │ ├── crowdin_sync.yml │ ├── e2e_testing.yaml │ ├── main_branch.yaml │ ├── pr-checks-nextgen.yml │ └── pr-checks.yaml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .nvmrc ├── .prettierignore ├── .releaserc.js ├── .vscode └── settings.json ├── .yarn └── patches │ ├── @firebase-messaging-npm-0.12.17-b743d37abd.patch │ └── @mui-material-npm-6.4.11-84c49ed24a.patch ├── .yarnrc.yml ├── LICENSE ├── README.md ├── __mocks__ └── @blockaid │ └── client.ts ├── apps ├── legacy │ ├── README.md │ ├── __mocks__ │ │ └── @blockaid │ │ │ └── client.ts │ ├── i18next-scanner.config.js │ ├── jest.config.js │ ├── manifest │ │ ├── _locales │ │ │ ├── de │ │ │ │ └── messages.json │ │ │ ├── en │ │ │ │ └── messages.json │ │ │ ├── es │ │ │ │ └── messages.json │ │ │ ├── hi │ │ │ │ └── messages.json │ │ │ ├── ja │ │ │ │ └── messages.json │ │ │ ├── ko │ │ │ │ └── messages.json │ │ │ ├── ru │ │ │ │ └── messages.json │ │ │ ├── tr │ │ │ │ └── messages.json │ │ │ └── zh_CN │ │ │ │ └── messages.json │ │ └── manifest.json │ ├── package.json │ ├── rsbuild.legacy.alpha.ts │ ├── rsbuild.legacy.common.ts │ ├── rsbuild.legacy.dev.ts │ ├── rsbuild.legacy.prod.ts │ ├── src │ │ ├── components │ │ │ ├── common │ │ │ │ ├── AddressK2.tsx │ │ │ │ ├── AppBackground.tsx │ │ │ │ ├── ArcProgress.tsx │ │ │ │ ├── BNInput.tsx │ │ │ │ ├── BalanceColumn.tsx │ │ │ │ ├── CameraAccessDeniedDialog.tsx │ │ │ │ ├── CameraAccessPromptDialog.tsx │ │ │ │ ├── ConfirmationTracker.tsx │ │ │ │ ├── ConnectionIndicatorK2.tsx │ │ │ │ ├── ContainedDropdown.tsx │ │ │ │ ├── CustomFees.tsx │ │ │ │ ├── CustomGasSettings.tsx │ │ │ │ ├── Dialog.tsx │ │ │ │ ├── Dropdown.tsx │ │ │ │ ├── EmptyContent.test.tsx │ │ │ │ ├── EmptyContent.tsx │ │ │ │ ├── FakeOnboardingBackground.tsx │ │ │ │ ├── FlexScrollbars.tsx │ │ │ │ ├── Flipper.tsx │ │ │ │ ├── FunctionIsOffline.tsx │ │ │ │ ├── FunctionIsUnavailable.tsx │ │ │ │ ├── GaslessFee.tsx │ │ │ │ ├── HallidayBanner.tsx │ │ │ │ ├── ImageWithFallback.tsx │ │ │ │ ├── InAppApprovalOverlay.tsx │ │ │ │ ├── InlineBold.tsx │ │ │ │ ├── InlineTokenEllipsis.tsx │ │ │ │ ├── InvalidQRCodeDialog.tsx │ │ │ │ ├── LedgerNano.tsx │ │ │ │ ├── LoadingOverlay.tsx │ │ │ │ ├── MagicSolanaLogo.tsx │ │ │ │ ├── MaliciousTokenWarning.tsx │ │ │ │ ├── MaliciousTxAlert.tsx │ │ │ │ ├── NetworkLogo.tsx │ │ │ │ ├── NetworkLogoK2.tsx │ │ │ │ ├── NotSupportedByWallet.tsx │ │ │ │ ├── Overlay.tsx │ │ │ │ ├── PageTitle.tsx │ │ │ │ ├── PasswordStrength.tsx │ │ │ │ ├── ProfitAndLoss.tsx │ │ │ │ ├── QRCodeWithLogo.tsx │ │ │ │ ├── SimpleAddress.tsx │ │ │ │ ├── SiteAvatar.tsx │ │ │ │ ├── SolanaLogoIcon.tsx │ │ │ │ ├── StyledNumberList.tsx │ │ │ │ ├── TestnetBanner.tsx │ │ │ │ ├── TextFieldLabel.tsx │ │ │ │ ├── TokenAmount.tsx │ │ │ │ ├── TokenCard.tsx │ │ │ │ ├── TokenCardWithBalance.tsx │ │ │ │ ├── TokenEllipsis.tsx │ │ │ │ ├── TokenIcon.tsx │ │ │ │ ├── TokenSelect.tsx │ │ │ │ ├── TokenSelector.tsx │ │ │ │ ├── TruncateFeeAmount.tsx │ │ │ │ ├── TxInProgress.tsx │ │ │ │ ├── TxWarningBox.tsx │ │ │ │ ├── VerticalStack.tsx │ │ │ │ ├── VirtualizedList.tsx │ │ │ │ ├── WalletChip.tsx │ │ │ │ ├── WalletLoading.tsx │ │ │ │ ├── account │ │ │ │ │ └── AccountSelectorButton.tsx │ │ │ │ ├── approval │ │ │ │ │ ├── ApprovalSection.tsx │ │ │ │ │ ├── TransactionDetailItem.tsx │ │ │ │ │ └── TxDetailsRow.tsx │ │ │ │ ├── fab │ │ │ │ │ └── FAB.tsx │ │ │ │ ├── header │ │ │ │ │ ├── Header.tsx │ │ │ │ │ ├── MenuItems.ts │ │ │ │ │ └── NetworkSwitcher │ │ │ │ │ │ ├── NetworkSwitcher.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ ├── infiniteScroll │ │ │ │ │ └── InfiniteScroll.tsx │ │ │ │ ├── scrollbars │ │ │ │ │ └── Scrollbars.tsx │ │ │ │ ├── seedless │ │ │ │ │ ├── SeedlessAuthPrompt.tsx │ │ │ │ │ ├── SeedlessUpdatingAccountDialog.tsx │ │ │ │ │ └── components │ │ │ │ │ │ ├── AuthenticationError.tsx │ │ │ │ │ │ ├── ExportError.tsx │ │ │ │ │ │ ├── ExportPending.tsx │ │ │ │ │ │ ├── FIDOChallenge.tsx │ │ │ │ │ │ ├── MfaChoicePrompt.tsx │ │ │ │ │ │ ├── PhraseReadyToExport.tsx │ │ │ │ │ │ ├── RecoveryMethod.tsx │ │ │ │ │ │ ├── TOTPChallenge.tsx │ │ │ │ │ │ └── WaitingForAuthentication.tsx │ │ │ │ ├── toastCardWithLink.tsx │ │ │ │ └── walletConnect │ │ │ │ │ └── useRequiredSession.ts │ │ │ ├── dialogs │ │ │ │ └── AnalyticsOptInDialog.tsx │ │ │ ├── icons │ │ │ │ ├── AvaxTokenIcon.tsx │ │ │ │ ├── BeadIcon.tsx │ │ │ │ ├── BitcoinLogo.tsx │ │ │ │ ├── BrandName.tsx │ │ │ │ ├── CameraAccessDeniedIcon.tsx │ │ │ │ ├── DangerIcon.tsx │ │ │ │ ├── FavStarIcon.tsx │ │ │ │ ├── GraphRingIcon.tsx │ │ │ │ ├── InvalidQRCodeIcon.tsx │ │ │ │ ├── QRCodeLogos.tsx │ │ │ │ └── VeloraIcon.tsx │ │ │ ├── ledger │ │ │ │ ├── LedgerConnector.tsx │ │ │ │ ├── LedgerConnectorSolana.tsx │ │ │ │ ├── LedgerLiveSupportButton.tsx │ │ │ │ └── LedgerTroublesSteps.tsx │ │ │ └── settings │ │ │ │ ├── SettingsHeader.tsx │ │ │ │ ├── SettingsMenu.tsx │ │ │ │ ├── components │ │ │ │ ├── ContactForm.tsx │ │ │ │ ├── ContactInfo.tsx │ │ │ │ ├── ContactListItem.tsx │ │ │ │ ├── ContactProfile.tsx │ │ │ │ └── StyledListItemButton.tsx │ │ │ │ ├── models.ts │ │ │ │ └── pages │ │ │ │ ├── AddContact.tsx │ │ │ │ ├── Advanced.tsx │ │ │ │ ├── ChangePassword.tsx │ │ │ │ ├── ConnectedSites.tsx │ │ │ │ ├── ContactList.tsx │ │ │ │ ├── Currencies.tsx │ │ │ │ ├── ExportRecoveryPhrase.tsx │ │ │ │ ├── Feedback.tsx │ │ │ │ ├── Language.tsx │ │ │ │ ├── Ledger.tsx │ │ │ │ ├── Legal.tsx │ │ │ │ ├── MainPage.tsx │ │ │ │ ├── Notifications.tsx │ │ │ │ ├── RecoveryMethods │ │ │ │ ├── AddNewRecoveryMethod.tsx │ │ │ │ ├── AuthenticatorDetails.tsx │ │ │ │ ├── AuthenticatorVerifyScreen.tsx │ │ │ │ ├── FIDODetails.tsx │ │ │ │ ├── RecoveryMethods.tsx │ │ │ │ └── RecoveryMethodsList.tsx │ │ │ │ ├── RecoveryPhrase.tsx │ │ │ │ └── SecurityAndPrivacy.tsx │ │ ├── contexts │ │ │ └── DialogContextProvider.tsx │ │ ├── hooks │ │ │ ├── useKeystoneScannerContents.tsx │ │ │ ├── useLedgerDisconnectedDialog.test.tsx │ │ │ ├── useLedgerDisconnectedDialog.tsx │ │ │ ├── useScopedToast.ts │ │ │ └── useSeedlessMfa.tsx │ │ ├── images │ │ │ ├── Core_logo_black_text_white_background.png │ │ │ ├── Core_logo_black_text_white_background.svg │ │ │ ├── Core_logo_white_text_black_background.png │ │ │ ├── Core_logo_white_text_black_background.svg │ │ │ ├── ai-avatar-text.svg │ │ │ ├── ai-avatar.svg │ │ │ ├── android-chrome-512x512.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── beta-logos │ │ │ │ ├── apple-touch-icon.png │ │ │ │ ├── favicon.svg │ │ │ │ ├── icon-16.png │ │ │ │ ├── icon-192.png │ │ │ │ ├── icon-256.png │ │ │ │ └── icon-32.png │ │ │ ├── core-ext-hero-hq.webm │ │ │ ├── favicon.ico │ │ │ ├── favicon.svg │ │ │ ├── halliday-icon.png │ │ │ ├── icon-128.png │ │ │ ├── icon-16.png │ │ │ ├── icon-192.png │ │ │ ├── icon-32.png │ │ │ ├── icon-48.png │ │ │ ├── keystone │ │ │ │ ├── keystone_onboarding_step_1.png │ │ │ │ ├── keystone_onboarding_step_2.png │ │ │ │ └── keystone_onboarding_step_3.png │ │ │ ├── logo-transparent.svg │ │ │ ├── logos │ │ │ │ ├── circle.png │ │ │ │ ├── coinbase.svg │ │ │ │ ├── jupiter-logo.svg │ │ │ │ ├── moonpay.svg │ │ │ │ ├── solana-logo.png │ │ │ │ ├── solana-logo.svg │ │ │ │ ├── solana-monochromatic.svg │ │ │ │ └── solana.png │ │ │ ├── no_image.svg │ │ │ ├── onboarding-background.png │ │ │ ├── onboarding-background.svg │ │ │ ├── solana-bg.svg │ │ │ ├── solana-logo.svg │ │ │ └── tokens │ │ │ │ └── eth.png │ │ ├── index.html │ │ ├── localization │ │ │ ├── externalPhrases.ts │ │ │ └── locales │ │ │ │ ├── de-DE │ │ │ │ └── translation.json │ │ │ │ ├── en │ │ │ │ └── translation.json │ │ │ │ ├── es-EM │ │ │ │ └── translation.json │ │ │ │ ├── es-ES │ │ │ │ └── translation.json │ │ │ │ ├── fr-FR │ │ │ │ └── translation.json │ │ │ │ ├── hi-IN │ │ │ │ └── translation.json │ │ │ │ ├── ja-JP │ │ │ │ └── translation.json │ │ │ │ ├── ko-KR │ │ │ │ └── translation.json │ │ │ │ ├── ru-RU │ │ │ │ └── translation.json │ │ │ │ ├── tr-TR │ │ │ │ └── translation.json │ │ │ │ ├── zh-CN │ │ │ │ └── translation.json │ │ │ │ └── zh-TW │ │ │ │ └── translation.json │ │ ├── monitoring │ │ │ └── initSentryForPopup.ts │ │ ├── pages │ │ │ ├── Accounts │ │ │ │ ├── AccountBalance.tsx │ │ │ │ ├── AccountDetailsView.tsx │ │ │ │ ├── AccountItemChip.tsx │ │ │ │ ├── Accounts.tsx │ │ │ │ ├── AddAccountError.tsx │ │ │ │ ├── AddWalletWithKeystoreFile.tsx │ │ │ │ ├── AddWalletWithLedger.tsx │ │ │ │ ├── AddWalletWithSeedPhrase.tsx │ │ │ │ ├── components │ │ │ │ │ ├── AccountDetailsAddressRow.tsx │ │ │ │ │ ├── AccountItem.tsx │ │ │ │ │ ├── AccountItemMenu.tsx │ │ │ │ │ ├── AccountListImported.tsx │ │ │ │ │ ├── AccountListPrimary.tsx │ │ │ │ │ ├── AccountName.tsx │ │ │ │ │ ├── AccountsActionButton.tsx │ │ │ │ │ ├── ConfirmAccountRemovalDialog.tsx │ │ │ │ │ ├── CurrentAddressSneakPeek.tsx │ │ │ │ │ ├── KeystoreFileConfirmation.tsx │ │ │ │ │ ├── KeystoreFileError.tsx │ │ │ │ │ ├── KeystoreFileUpload.tsx │ │ │ │ │ ├── MenuFilterItem.tsx │ │ │ │ │ ├── NameYourWallet.tsx │ │ │ │ │ ├── NoAccountsFound.tsx │ │ │ │ │ ├── OverflowingTypography.tsx │ │ │ │ │ ├── RenameDialog.tsx │ │ │ │ │ ├── WalletContainer.tsx │ │ │ │ │ ├── WalletHeader.tsx │ │ │ │ │ └── WalletTypeIcon.tsx │ │ │ │ └── hooks │ │ │ │ │ ├── useAccountRemoval.tsx │ │ │ │ │ ├── useAccountRename.tsx │ │ │ │ │ ├── useEntityRename.tsx │ │ │ │ │ ├── useWalletRename.tsx │ │ │ │ │ └── useWalletTypeName.tsx │ │ │ ├── Activity │ │ │ │ └── Activity.tsx │ │ │ ├── ApproveAction │ │ │ │ ├── AvalancheSignTx.tsx │ │ │ │ ├── GenericApprovalScreen.tsx │ │ │ │ ├── SelectWallet.tsx │ │ │ │ ├── SetDeveloperMode.tsx │ │ │ │ ├── TxBatchApprovalScreen.tsx │ │ │ │ ├── UpdateContacts.tsx │ │ │ │ ├── components │ │ │ │ │ ├── ApproveAddDelegator.tsx │ │ │ │ │ ├── ApproveAddPermissionlessDelegator.tsx │ │ │ │ │ ├── ApproveAddPermissionlessValidator.tsx │ │ │ │ │ ├── ApproveAddSubnetValidator.tsx │ │ │ │ │ ├── ApproveAddValidator.tsx │ │ │ │ │ ├── ApproveBaseTx.tsx │ │ │ │ │ ├── ApproveConvertSubnetToL1.tsx │ │ │ │ │ ├── ApproveCreateChain.tsx │ │ │ │ │ ├── ApproveCreateSubnet.tsx │ │ │ │ │ ├── ApproveDisableL1Validator.tsx │ │ │ │ │ ├── ApproveExportTx.tsx │ │ │ │ │ ├── ApproveImportTx.tsx │ │ │ │ │ ├── ApproveIncreaseL1ValidatorBalance.tsx │ │ │ │ │ ├── ApproveRegisterL1Validator.tsx │ │ │ │ │ ├── ApproveRemoveSubnetValidator.tsx │ │ │ │ │ ├── ApproveSetL1ValidatorWeight.tsx │ │ │ │ │ ├── AvalancheTxHeader.tsx │ │ │ │ │ ├── AvaxAmount.tsx │ │ │ │ │ ├── BlockchainGenesisFile.tsx │ │ │ │ │ ├── DetailedCardWrapper.tsx │ │ │ │ │ ├── DeviceApproval.tsx │ │ │ │ │ ├── ExcessiveBurnWarningDialog.tsx │ │ │ │ │ ├── TransactionDetailsCardContent.tsx │ │ │ │ │ └── TruncatedIdentifier.tsx │ │ │ │ └── hooks │ │ │ │ │ └── useFeeCustomizer.tsx │ │ │ ├── Bridge │ │ │ │ ├── Bridge.tsx │ │ │ │ ├── BridgeTransactionStatus.tsx │ │ │ │ └── components │ │ │ │ │ ├── BridgeCard.tsx │ │ │ │ │ ├── BridgeForm.tsx │ │ │ │ │ ├── BridgeFormSkeleton.tsx │ │ │ │ │ ├── BridgeSanctions.tsx │ │ │ │ │ ├── BridgeTypeFootnote.tsx │ │ │ │ │ ├── BridgeUnknownNetwork.tsx │ │ │ │ │ ├── ElapsedTimer.tsx │ │ │ │ │ ├── NetworkSelector.tsx │ │ │ │ │ └── OffloadTimerTooltip.tsx │ │ │ ├── Collectibles │ │ │ │ ├── CollectibleDetails.tsx │ │ │ │ ├── CollectibleSend.tsx │ │ │ │ ├── Collectibles.tsx │ │ │ │ ├── SendEVMCollectible.tsx │ │ │ │ ├── components │ │ │ │ │ ├── CollectibleGrid.tsx │ │ │ │ │ ├── CollectibleList.tsx │ │ │ │ │ ├── CollectibleListEmpty.tsx │ │ │ │ │ ├── CollectibleMedia.tsx │ │ │ │ │ ├── CollectibleSkeleton.tsx │ │ │ │ │ ├── CollectibleWrapper.tsx │ │ │ │ │ └── ImageWrapper.tsx │ │ │ │ ├── hooks │ │ │ │ │ ├── useCollectibleFromParams.tsx │ │ │ │ │ └── useSetCollectibleParams.tsx │ │ │ │ └── utils.ts │ │ │ ├── DeFi │ │ │ │ ├── DeFi.tsx │ │ │ │ ├── DefiProtocolDetails.tsx │ │ │ │ └── components │ │ │ │ │ ├── DefiErrorState.tsx │ │ │ │ │ ├── DefiPortfolioCommon.tsx │ │ │ │ │ ├── DefiPortfolioInsurance.tsx │ │ │ │ │ ├── DefiPortfolioItemGroup.tsx │ │ │ │ │ ├── DefiPortfolioLending.tsx │ │ │ │ │ ├── DefiPortfolioPerpetual.tsx │ │ │ │ │ ├── DefiPortfolioRewards.tsx │ │ │ │ │ ├── DefiPortfolioVesting.tsx │ │ │ │ │ ├── DefiProtocolDetailsHeader.tsx │ │ │ │ │ ├── DefiProtocolListItem.tsx │ │ │ │ │ ├── DefiTokenAvatarGroup.tsx │ │ │ │ │ └── DefiZeroState.tsx │ │ │ ├── ExportPrivateKey │ │ │ │ ├── EnterPassword.tsx │ │ │ │ ├── ExportPrivateKey.tsx │ │ │ │ └── ShowPrivateKey.tsx │ │ │ ├── Fireblocks │ │ │ │ ├── ConnectBitcoinWallet.tsx │ │ │ │ ├── ImportFireblocksWithWalletConnect.tsx │ │ │ │ ├── components │ │ │ │ │ ├── FireblocksAvatar.tsx │ │ │ │ │ └── FireblocksBitcoinDialog.tsx │ │ │ │ └── hooks │ │ │ │ │ └── useFireblocksErrorMessage.ts │ │ │ ├── Home │ │ │ │ ├── Home.tsx │ │ │ │ └── components │ │ │ │ │ └── Portfolio │ │ │ │ │ ├── Assets.tsx │ │ │ │ │ ├── NetworkWidget │ │ │ │ │ ├── ActiveNetworkWidget.tsx │ │ │ │ │ ├── Assetlist.tsx │ │ │ │ │ ├── NetworkList.tsx │ │ │ │ │ ├── NetworksWidget.tsx │ │ │ │ │ ├── PchainActiveNetworkWidgetContent.tsx │ │ │ │ │ ├── SeeAllNetworksButton.tsx │ │ │ │ │ ├── XchainActiveNetworkWidgetContent.tsx │ │ │ │ │ ├── ZeroWidget.tsx │ │ │ │ │ └── common │ │ │ │ │ │ └── NetworkCard.tsx │ │ │ │ │ ├── Portfolio.tsx │ │ │ │ │ ├── Prompt │ │ │ │ │ ├── GradientElements.tsx │ │ │ │ │ ├── Prompt.tsx │ │ │ │ │ ├── PromptElements.tsx │ │ │ │ │ ├── Typewriter.tsx │ │ │ │ │ └── models.ts │ │ │ │ │ ├── TokenList.tsx │ │ │ │ │ ├── TokenListItem.tsx │ │ │ │ │ ├── WalletBalances.tsx │ │ │ │ │ └── WalletIsEmpty.tsx │ │ │ ├── ImportPrivateKey │ │ │ │ ├── ImportPrivateKey.tsx │ │ │ │ └── components │ │ │ │ │ ├── DerivedAddress.tsx │ │ │ │ │ └── DuplicatedAccountDialog.tsx │ │ │ ├── ImportWithWalletConnect │ │ │ │ ├── ImportWithWalletConnect.tsx │ │ │ │ ├── components │ │ │ │ │ ├── WalletConnectCircledIcon.tsx │ │ │ │ │ ├── WalletConnectConnector.tsx │ │ │ │ │ ├── WalletConnectQRCode.tsx │ │ │ │ │ ├── WalletConnectStatusMessage.tsx │ │ │ │ │ ├── WalletConnectURIField.tsx │ │ │ │ │ └── utils │ │ │ │ │ │ └── getColorForStatus.ts │ │ │ │ └── index.ts │ │ │ ├── Ledger │ │ │ │ ├── Connect.tsx │ │ │ │ ├── LedgerDeriveSolanaAddresses.tsx │ │ │ │ ├── LedgerDisconnected.tsx │ │ │ │ ├── LedgerIncorrectApp.tsx │ │ │ │ ├── LedgerIncorrectDevice.tsx │ │ │ │ ├── LedgerRegisterBtcWalletPolicy.tsx │ │ │ │ ├── LedgerSolanaAddressPrompt.tsx │ │ │ │ ├── LedgerTroubleshooting.tsx │ │ │ │ ├── LedgerWrongVersion.tsx │ │ │ │ ├── LedgerWrongVersionOverlay.tsx │ │ │ │ └── models.ts │ │ │ ├── ManageCollectibles │ │ │ │ ├── ManageCollectibles.tsx │ │ │ │ └── ManageCollectiblesList.tsx │ │ │ ├── ManageTokens │ │ │ │ ├── AddToken.tsx │ │ │ │ ├── AddTokenApproval.tsx │ │ │ │ ├── ManageTokens.tsx │ │ │ │ └── ManageTokensList.tsx │ │ │ ├── Network │ │ │ │ ├── AddCustomNetworkPopup.tsx │ │ │ │ └── SwitchActiveNetwork.tsx │ │ │ ├── Networks │ │ │ │ ├── AddNetwork.tsx │ │ │ │ ├── CustomsTab.tsx │ │ │ │ ├── EditNetwork.tsx │ │ │ │ ├── FavoritesTab.tsx │ │ │ │ ├── NetworkDetails.tsx │ │ │ │ ├── NetworkDetailsDialogs.tsx │ │ │ │ ├── NetworkForm.tsx │ │ │ │ ├── NetworkRpcHeaders.tsx │ │ │ │ ├── NetworkRpcHeadersManager.tsx │ │ │ │ ├── Networks.tsx │ │ │ │ ├── NetworksTab.tsx │ │ │ │ ├── common │ │ │ │ │ ├── NetworkList.tsx │ │ │ │ │ ├── NetworkListItem.ts │ │ │ │ │ └── NetworkLogo.ts │ │ │ │ └── index.tsx │ │ │ ├── Onboarding │ │ │ │ ├── Onboarding.tsx │ │ │ │ ├── components │ │ │ │ │ ├── DerivationPathDropDown.tsx │ │ │ │ │ ├── DerivedAddresses.tsx │ │ │ │ │ ├── LanguageSelector.tsx │ │ │ │ │ ├── OnboardButton.tsx │ │ │ │ │ ├── OnboardingStepHeader.tsx │ │ │ │ │ ├── PageNav.tsx │ │ │ │ │ ├── PageTracker.tsx │ │ │ │ │ ├── TypographyLink.tsx │ │ │ │ │ └── WordsLengthSelector.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── pages │ │ │ │ │ ├── AnalyticsConsent.tsx │ │ │ │ │ ├── CreatePassword.tsx │ │ │ │ │ ├── CreateWallet │ │ │ │ │ │ ├── ConfirmMnemonic.tsx │ │ │ │ │ │ ├── ConfirmPhrase.tsx │ │ │ │ │ │ ├── CopyPhrase.tsx │ │ │ │ │ │ ├── CreateWallet.tsx │ │ │ │ │ │ ├── Mnemonic.tsx │ │ │ │ │ │ └── ShowMnemonic.tsx │ │ │ │ │ ├── ImportWallet.tsx │ │ │ │ │ ├── Keystone │ │ │ │ │ │ ├── Keystone.tsx │ │ │ │ │ │ └── KeystoneQRCodeScanner.tsx │ │ │ │ │ ├── Ledger │ │ │ │ │ │ ├── LedgerConnect.tsx │ │ │ │ │ │ └── LedgerTrouble.tsx │ │ │ │ │ ├── Seedless │ │ │ │ │ │ ├── RecoveryMethods.tsx │ │ │ │ │ │ ├── RecoveryMethodsLogin.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── AppleButton.tsx │ │ │ │ │ │ │ ├── ExistingWalletButton.tsx │ │ │ │ │ │ │ ├── ExistingWalletOptions.tsx │ │ │ │ │ │ │ ├── GoogleButton.tsx │ │ │ │ │ │ │ └── MethodCard.tsx │ │ │ │ │ │ └── modals │ │ │ │ │ │ │ ├── AuthenticatorModal.tsx │ │ │ │ │ │ │ ├── FIDOModal.tsx │ │ │ │ │ │ │ ├── TOTPModal.tsx │ │ │ │ │ │ │ └── VerifyGoBackModal.tsx │ │ │ │ │ └── Welcome │ │ │ │ │ │ ├── SignUpWithSeedless.tsx │ │ │ │ │ │ └── Welcome.tsx │ │ │ │ └── utils │ │ │ │ │ ├── getRandomMnemonicWord.ts │ │ │ │ │ ├── splitSeedPhrase.test.ts │ │ │ │ │ └── splitSeedPhrase.ts │ │ │ ├── Permissions │ │ │ │ ├── Permissions.tsx │ │ │ │ ├── components │ │ │ │ │ ├── AccountsDropdown.tsx │ │ │ │ │ ├── AlertBox.tsx │ │ │ │ │ ├── AlertDialog.tsx │ │ │ │ │ └── WarningBox.tsx │ │ │ │ └── useCurrentDomain.ts │ │ │ ├── Receive │ │ │ │ └── Receive.tsx │ │ │ ├── SeedlessPopups │ │ │ │ ├── SeedlessAuthPopup.tsx │ │ │ │ ├── SeedlessExportPopup.tsx │ │ │ │ ├── SeedlessRemoveTotp.tsx │ │ │ │ └── SeedlessUpdateRecoveryMethod.tsx │ │ │ ├── Send │ │ │ │ ├── Send.tsx │ │ │ │ ├── components │ │ │ │ │ ├── AddressDropdownList.tsx │ │ │ │ │ ├── AddressDropdownListItem.tsx │ │ │ │ │ ├── AddressDropdownListMyAccounts.tsx │ │ │ │ │ ├── ContactAddress.tsx │ │ │ │ │ ├── ContactInput.tsx │ │ │ │ │ ├── ContactSelect.tsx │ │ │ │ │ ├── LoadingSendForm.tsx │ │ │ │ │ ├── SendAVM.tsx │ │ │ │ │ ├── SendBTC.tsx │ │ │ │ │ ├── SendEVM.tsx │ │ │ │ │ ├── SendForm.tsx │ │ │ │ │ ├── SendPVM.tsx │ │ │ │ │ ├── SendSVM.tsx │ │ │ │ │ └── TruncatedAddress.tsx │ │ │ │ ├── hooks │ │ │ │ │ ├── useIdentifyAddress.ts │ │ │ │ │ ├── useSend │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── models.ts │ │ │ │ │ │ ├── useAVMSend.ts │ │ │ │ │ │ ├── useBTCSend.ts │ │ │ │ │ │ ├── useEVMSend.ts │ │ │ │ │ │ ├── usePVMSend.ts │ │ │ │ │ │ └── useSVMSend.ts │ │ │ │ │ └── useValidAddressFromParams.ts │ │ │ │ ├── models.ts │ │ │ │ └── utils │ │ │ │ │ ├── buildSendTx.test.ts │ │ │ │ │ ├── buildSendTx.ts │ │ │ │ │ ├── correctAddressByPrefix.test.ts │ │ │ │ │ ├── correctAddressByPrefix.ts │ │ │ │ │ ├── getMaxUtxos.test.ts │ │ │ │ │ ├── getMaxUtxos.ts │ │ │ │ │ └── sendErrorMessages.ts │ │ │ ├── SignMessage │ │ │ │ ├── SignMessage.tsx │ │ │ │ ├── components │ │ │ │ │ ├── EthSign.tsx │ │ │ │ │ ├── PersonalSign.tsx │ │ │ │ │ ├── ScrollableMessageCard.tsx │ │ │ │ │ ├── SignData.tsx │ │ │ │ │ ├── SignDataV3.tsx │ │ │ │ │ ├── SignDataV4.tsx │ │ │ │ │ └── SignError.tsx │ │ │ │ └── hooks │ │ │ │ │ └── useIsIntersecting.ts │ │ │ ├── SignTransaction │ │ │ │ ├── components │ │ │ │ │ ├── ApprovalTxDetails.tsx │ │ │ │ │ ├── FireblocksApproval │ │ │ │ │ │ ├── FireblocksApprovalOverlay.tsx │ │ │ │ │ │ └── FireblocksApprovalReview.tsx │ │ │ │ │ ├── KeystoneApprovalOverlay.tsx │ │ │ │ │ ├── LedgerApprovalDialog.tsx │ │ │ │ │ ├── LedgerApprovalOverlay.tsx │ │ │ │ │ ├── NftAccordion.tsx │ │ │ │ │ ├── RawTransactionData.tsx │ │ │ │ │ ├── RemoteApproval │ │ │ │ │ │ ├── RemoteApprovalConfirmation.tsx │ │ │ │ │ │ └── RemoteApprovalDialog.tsx │ │ │ │ │ ├── SignTxErrorBoundary.tsx │ │ │ │ │ ├── SpendLimitInfo │ │ │ │ │ │ ├── CustomSpendLimit.tsx │ │ │ │ │ │ ├── NftSpendLimit.tsx │ │ │ │ │ │ ├── SpendLimitInfo.tsx │ │ │ │ │ │ └── TokenSpendLimit.tsx │ │ │ │ │ ├── TransactionActionInfo │ │ │ │ │ │ ├── ApproveContractCallDetails.tsx │ │ │ │ │ │ ├── ApproveNftCollectionDetails.tsx │ │ │ │ │ │ ├── ApproveNftDetails.tsx │ │ │ │ │ │ ├── ApproveSendDetails.tsx │ │ │ │ │ │ ├── ApproveTokenDetails.tsx │ │ │ │ │ │ └── TransactionActionInfo.tsx │ │ │ │ │ ├── TransactionErrorDialog.tsx │ │ │ │ │ ├── TransactionTokenCard.tsx │ │ │ │ │ ├── TxBalanceChange.tsx │ │ │ │ │ └── WalletConnectApproval │ │ │ │ │ │ ├── WalletConnectApprovalConnect.tsx │ │ │ │ │ │ ├── WalletConnectApprovalOverlay.tsx │ │ │ │ │ │ ├── WalletConnectApprovalReview.tsx │ │ │ │ │ │ └── WalletConnectApprovalSent.tsx │ │ │ │ ├── hooks │ │ │ │ │ └── useSignTransactionHeader.ts │ │ │ │ ├── models.ts │ │ │ │ └── utils │ │ │ │ │ ├── getActiveStepForRemoteApproval.ts │ │ │ │ │ └── getToAddressesFromTransaction.ts │ │ │ ├── Swap │ │ │ │ ├── Swap.tsx │ │ │ │ ├── components │ │ │ │ │ ├── SlippageToolTip.tsx │ │ │ │ │ ├── SwapEngineNotice.tsx │ │ │ │ │ ├── SwapError.tsx │ │ │ │ │ ├── SwapPendingToast.tsx │ │ │ │ │ ├── SwapRefreshTimer.tsx │ │ │ │ │ └── TransactionDetails.tsx │ │ │ │ ├── hooks │ │ │ │ │ ├── useSwapStateFunctions.ts │ │ │ │ │ ├── useSwapTokens.ts │ │ │ │ │ └── useTokensBySymbols.ts │ │ │ │ ├── models.ts │ │ │ │ └── utils │ │ │ │ │ ├── calculateRate.ts │ │ │ │ │ └── index.tsx │ │ │ └── Wallet │ │ │ │ ├── DeleteAccounts.tsx │ │ │ │ ├── GetAddressesInRange.tsx │ │ │ │ ├── RenameAccount.tsx │ │ │ │ ├── RenameWallet.tsx │ │ │ │ ├── SwitchAccount.tsx │ │ │ │ ├── TokenFlow.tsx │ │ │ │ ├── WalletLocked.tsx │ │ │ │ ├── WalletRecentTxs.tsx │ │ │ │ ├── components │ │ │ │ ├── History │ │ │ │ │ ├── components │ │ │ │ │ │ ├── ActivityCard │ │ │ │ │ │ │ ├── ActivityCard.tsx │ │ │ │ │ │ │ ├── ActivityCardAmount.tsx │ │ │ │ │ │ │ ├── ActivityCardDetails.tsx │ │ │ │ │ │ │ ├── ActivityCardIcon.tsx │ │ │ │ │ │ │ ├── ActivityCardSummary.tsx │ │ │ │ │ │ │ ├── PchainActivityCard.tsx │ │ │ │ │ │ │ ├── PrimaryNetworkMethodIcon.tsx │ │ │ │ │ │ │ └── XchainActivityCard.tsx │ │ │ │ │ │ └── InProgressBridge │ │ │ │ │ │ │ ├── InProgressBridgeActivityCard.tsx │ │ │ │ │ │ │ └── InProgressBridgeIcon.tsx │ │ │ │ │ └── useBlockchainNames.ts │ │ │ │ ├── NoTransactions.tsx │ │ │ │ └── WalletExtensionButton.tsx │ │ │ │ └── models.ts │ │ ├── popup │ │ │ ├── AppRoutes.tsx │ │ │ ├── ApprovalRoutes.tsx │ │ │ ├── LoadingContent.tsx │ │ │ ├── OfflineContent.tsx │ │ │ ├── index.tsx │ │ │ └── popup.tsx │ │ ├── template.html │ │ └── types │ │ │ └── images.d.ts │ └── tsconfig.json └── next │ ├── README.md │ ├── i18next-scanner.config.js │ ├── jest.config.js │ ├── manifest │ ├── _locales │ │ ├── de │ │ │ └── messages.json │ │ ├── en │ │ │ └── messages.json │ │ ├── es │ │ │ └── messages.json │ │ ├── hi │ │ │ └── messages.json │ │ ├── ja │ │ │ └── messages.json │ │ ├── ko │ │ │ └── messages.json │ │ ├── ru │ │ │ └── messages.json │ │ ├── tr │ │ │ └── messages.json │ │ └── zh_CN │ │ │ └── messages.json │ └── manifest.json │ ├── package.json │ ├── rsbuild.next.alpha.ts │ ├── rsbuild.next.common.ts │ ├── rsbuild.next.dev.ts │ ├── rsbuild.next.prod.ts │ ├── src │ ├── components │ │ └── BrandName │ │ │ ├── BrandName.tsx │ │ │ └── index.ts │ ├── images │ │ ├── Core_logo_black_text_white_background.png │ │ ├── Core_logo_black_text_white_background.svg │ │ ├── Core_logo_white_text_black_background.png │ │ ├── Core_logo_white_text_black_background.svg │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── beta-logos │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon.svg │ │ │ ├── icon-16.png │ │ │ ├── icon-192.png │ │ │ ├── icon-256.png │ │ │ └── icon-32.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-192.png │ │ ├── icon-32.png │ │ ├── icon-48.png │ │ ├── logo-transparent.svg │ │ └── no_image.svg │ ├── index.html │ ├── localization │ │ ├── externalPhrases.ts │ │ ├── init.ts │ │ └── locales │ │ │ ├── de-DE │ │ │ └── translation.json │ │ │ ├── en │ │ │ └── translation.json │ │ │ ├── es-EM │ │ │ └── translation.json │ │ │ ├── es-ES │ │ │ └── translation.json │ │ │ ├── fr-FR │ │ │ └── translation.json │ │ │ ├── hi-IN │ │ │ └── translation.json │ │ │ ├── ja-JP │ │ │ └── translation.json │ │ │ ├── ko-KR │ │ │ └── translation.json │ │ │ ├── ru-RU │ │ │ └── translation.json │ │ │ ├── tr-TR │ │ │ └── translation.json │ │ │ ├── zh-CN │ │ │ └── translation.json │ │ │ └── zh-TW │ │ │ └── translation.json │ ├── monitoring │ │ └── initSentryForPopup.ts │ ├── pages │ │ ├── LockScreen │ │ │ ├── LockScreen.tsx │ │ │ └── index.ts │ │ └── Onboarding │ │ │ ├── Onboarding.test.tsx │ │ │ ├── Onboarding.tsx │ │ │ └── index.tsx │ └── popup │ │ ├── app.tsx │ │ └── index.tsx │ └── tsconfig.json ├── babel.config.js ├── build-scripts ├── getEnvVars.ts ├── manifestHelpers.js ├── readCoreCliArgument.mjs └── zipscript.mjs ├── commitlint.config.js ├── docs ├── 01-Architecture.md ├── 02-Background-script.md ├── 03-Storage.md ├── 04-Frontend.md ├── 05-Dapp-connections.md ├── 06-Ledger.md ├── 07-Localization.md ├── 08-Analytics-and-Feature-Flags.md ├── 09-Keystone.md ├── 10-WalletConnect.md ├── 11-Fireblocks.md ├── 11-Seedless.md ├── README.md ├── diagrams │ ├── README.md │ ├── address-derivation.drawio │ ├── architecture.drawio │ ├── background-architecture.drawio │ ├── fireblocks-import.drawio │ ├── fireblocks-signing.drawio │ ├── inpage-provider-architecture.drawio │ ├── ledger-architecture.drawio │ ├── ledger-signing-flow.drawio │ ├── transaction-flow.drawio │ ├── wallet-connect-pairing.drawio │ ├── wallet-connect-signing.drawio │ └── window-ethereum-proxy.drawio └── images │ ├── address-derivation.drawio.png │ ├── architecture.png │ ├── background-architecture.png │ ├── fireblocks-import.png │ ├── fireblocks-signing.png │ ├── inpage-initialization-process.png │ ├── inpage-provider-communication.png │ ├── ledger-architecture.png │ ├── ledger-signing-flow.png │ ├── screenshot1.png │ ├── screenshot2.png │ ├── seedless-onboarding-flow.png │ ├── seedless-signing-flow.png │ ├── wallet-connect-pairing.png │ └── wallet-connect-signing.png ├── eslint.config.mjs ├── jest.config.js ├── package.json ├── packages ├── common │ ├── README.md │ ├── jest.config.cjs │ ├── package.json │ ├── src │ │ ├── constants.ts │ │ ├── feature-flags.ts │ │ ├── index.ts │ │ ├── initI18n.ts │ │ ├── monitoring │ │ │ ├── index.ts │ │ │ ├── sentryCaptureException.ts │ │ │ └── sharedSentryConfig.ts │ │ ├── script-names.ts │ │ └── utils │ │ │ ├── account.ts │ │ │ ├── accounts │ │ │ ├── accountTypeGuards.ts │ │ │ └── index.ts │ │ │ ├── actions │ │ │ └── getUpdatedActionData.ts │ │ │ ├── address.ts │ │ │ ├── approveSeedlessRegistration.test.ts │ │ │ ├── approveSeedlessRegistration.ts │ │ │ ├── array.ts │ │ │ ├── assertions.ts │ │ │ ├── balance │ │ │ ├── getPriceChangeValues.test.ts │ │ │ ├── getPriceChangeValues.ts │ │ │ ├── getTokenValue.test.ts │ │ │ ├── getTokenValue.ts │ │ │ ├── groupTokensByType.ts │ │ │ ├── index.ts │ │ │ ├── isTokenWithBalanceAVM.test.ts │ │ │ ├── isTokenWithBalanceAVM.ts │ │ │ ├── isTokenWithBalancePVM.test.ts │ │ │ └── isTokenWithBalancePVM.ts │ │ │ ├── bigintToBig.test.ts │ │ │ ├── bigintToBig.ts │ │ │ ├── bridge │ │ │ ├── blockchainConversion.test.ts │ │ │ ├── blockchainConversion.ts │ │ │ ├── bridgeEventFilters.ts │ │ │ ├── filterBridgeStateToNetwork.ts │ │ │ ├── findMatchingBridgeAsset.ts │ │ │ ├── getBridgedAssetSymbol.ts │ │ │ ├── getNativeTokenSymbol.ts │ │ │ ├── index.ts │ │ │ ├── isAddressBlockedError.ts │ │ │ └── isUnifiedBridgeTransfer.ts │ │ │ ├── bridgeTransactionUtils.ts │ │ │ ├── caipConversion.ts │ │ │ ├── calculateGasAndFees.ts │ │ │ ├── calculateTotalBalance.test.ts │ │ │ ├── calculateTotalBalance.ts │ │ │ ├── canSkipApproval.ts │ │ │ ├── constants.ts │ │ │ ├── createMnemonicPhrase.ts │ │ │ ├── distributiveomit.ts │ │ │ ├── encoding.ts │ │ │ ├── environment.ts │ │ │ ├── errors │ │ │ ├── errorHelpers.test.ts │ │ │ ├── errorHelpers.ts │ │ │ └── index.ts │ │ │ ├── exponentialBackoff.test.ts │ │ │ ├── exponentialBackoff.ts │ │ │ ├── extensionUtils.ts │ │ │ ├── fetchAndVerify.ts │ │ │ ├── filterFalsyValues.ts │ │ │ ├── findTokenForAsset.test.ts │ │ │ ├── findTokenForAsset.ts │ │ │ ├── fireblocks │ │ │ ├── getFireblocksBtcAccessErrorCode.test.ts │ │ │ ├── getFireblocksBtcAccessErrorCode.ts │ │ │ └── isFireblocksApiSupported.ts │ │ │ ├── getAccountKey.test.ts │ │ │ ├── getAccountKey.ts │ │ │ ├── getAddressForChain.test.ts │ │ │ ├── getAddressForChain.ts │ │ │ ├── getCoreWebUrl.test.ts │ │ │ ├── getCoreWebUrl.ts │ │ │ ├── getDefaultChainIds.ts │ │ │ ├── getEnabledBridgeTypes.ts │ │ │ ├── getExplorerAddress.ts │ │ │ ├── getHexStringToBytes.ts │ │ │ ├── getNftMetadata.test.ts │ │ │ ├── getNftMetadata.ts │ │ │ ├── getSyncDomain.ts │ │ │ ├── handleTxOutcome.ts │ │ │ ├── hasAccountBalances.test.ts │ │ │ ├── hasAccountBalances.ts │ │ │ ├── hasUnconfirmedBalance.ts │ │ │ ├── history │ │ │ ├── getAvaxAssetId.ts │ │ │ ├── index.ts │ │ │ ├── isTxHistoryItem.test.ts │ │ │ └── isTxHistoryItem.ts │ │ │ ├── incrementalPromiseResolve.test.ts │ │ │ ├── incrementalPromiseResolve.ts │ │ │ ├── index.ts │ │ │ ├── ipsfResolverWithFallback.ts │ │ │ ├── isActiveTab.ts │ │ │ ├── isAddressValid.test.ts │ │ │ ├── isAddressValid.ts │ │ │ ├── isBitcoin.ts │ │ │ ├── isBtcAddressInNetwork.ts │ │ │ ├── isContactValid.test.ts │ │ │ ├── isContactValid.ts │ │ │ ├── isFailedToFetchError.test.ts │ │ │ ├── isFailedToFetchError.ts │ │ │ ├── isLedgerVersionCompatible.test.ts │ │ │ ├── isLedgerVersionCompatible.ts │ │ │ ├── isLockStateChangedEvent.ts │ │ │ ├── isPrimarySubnet.ts │ │ │ ├── isSupportedBrowser.test.ts │ │ │ ├── isSupportedBrowser.ts │ │ │ ├── isSwimmerNetwork.ts │ │ │ ├── isTokenMalicious.ts │ │ │ ├── isValidAddress.test.ts │ │ │ ├── isValidXpAddress.ts │ │ │ ├── isWalletStateUpdateEvent.ts │ │ │ ├── jsonRpcEngine.ts │ │ │ ├── keystore │ │ │ ├── cryptoHelpers.ts │ │ │ ├── index.ts │ │ │ ├── keystore-fixtures │ │ │ │ ├── index.ts │ │ │ │ ├── keystore-v2.json │ │ │ │ ├── keystore-v3.json │ │ │ │ ├── keystore-v4.json │ │ │ │ ├── keystore-v5.json │ │ │ │ ├── keystore-v6-private-key.json │ │ │ │ └── keystore-v6.json │ │ │ ├── keystore.test.ts │ │ │ └── keystore.ts │ │ │ ├── logging.ts │ │ │ ├── lowerCaseKeys.ts │ │ │ ├── makeBNLike.ts │ │ │ ├── measureDuration.test.ts │ │ │ ├── measureDuration.ts │ │ │ ├── network │ │ │ ├── addGlacierAPIKeyIdNeeded.test.ts │ │ │ ├── addGlacierAPIKeyIfNeeded.ts │ │ │ ├── buildGlacierAuthHeaders.ts │ │ │ ├── getProviderForNetwork.test.ts │ │ │ ├── getProviderForNetwork.ts │ │ │ ├── isAvalancheNetwork.ts │ │ │ ├── isAvalanchePchainNetwork.test.ts │ │ │ ├── isAvalanchePchainNetwork.ts │ │ │ ├── isAvalancheXchainNetwork.test.ts │ │ │ ├── isAvalancheXchainNetwork.ts │ │ │ ├── isBitcoinNetwork.ts │ │ │ ├── isEthereumNetwork.ts │ │ │ ├── isSolanaNetwork.ts │ │ │ └── isValidHttpHeader.ts │ │ │ ├── newsletter.ts │ │ │ ├── nfts │ │ │ ├── getSmallImageForNFT.ts │ │ │ ├── isNFT.ts │ │ │ ├── metadataParser.ts │ │ │ └── nftTypesUtils.ts │ │ │ ├── noop.ts │ │ │ ├── normalizeBalance.ts │ │ │ ├── number.ts │ │ │ ├── object.ts │ │ │ ├── onPageActivated.test.ts │ │ │ ├── onPageActivated.ts │ │ │ ├── openFullscreenTab.ts │ │ │ ├── promiseResolver.ts │ │ │ ├── seedPhraseValidation.ts │ │ │ ├── seedless │ │ │ ├── authenticateWithApple.test.ts │ │ │ ├── authenticateWithApple.ts │ │ │ ├── authenticateWithGoogle.test.ts │ │ │ ├── authenticateWithGoogle.ts │ │ │ ├── fido │ │ │ │ ├── convertRequest.test.ts │ │ │ │ ├── convertRequest.ts │ │ │ │ ├── convertResult.test.ts │ │ │ │ ├── convertResult.ts │ │ │ │ ├── index.ts │ │ │ │ ├── launchFidoFlow.test.ts │ │ │ │ ├── launchFidoFlow.ts │ │ │ │ ├── seedless-utils.ts │ │ │ │ └── validateResponse.ts │ │ │ ├── getCubeSigner.ts │ │ │ ├── getOidcTokenProvider.test.ts │ │ │ ├── getOidcTokenProvider.ts │ │ │ ├── getSignerToken.test.ts │ │ │ ├── getSignerToken.ts │ │ │ ├── launchWebAuthFlow.ts │ │ │ └── seedlessEventFilters.ts │ │ │ ├── send │ │ │ ├── btcSendUtils.test.ts │ │ │ └── btcSendUtils.ts │ │ │ ├── shouldUseWalletConnectApproval.test.ts │ │ │ ├── shouldUseWalletConnectApproval.ts │ │ │ ├── stringToBigint.ts │ │ │ ├── stripAddressPrefix.ts │ │ │ ├── sumByProperty.test.ts │ │ │ ├── sumByProperty.ts │ │ │ ├── toArrayBuffer.ts │ │ │ ├── truncateAddress.ts │ │ │ ├── typeUtils.ts │ │ │ ├── updateIfDifferent.ts │ │ │ └── walletConnectEventFilters.ts │ └── tsconfig.json ├── content-script │ ├── README.md │ ├── package.json │ ├── rsbuild.content-script.common.ts │ ├── rsbuild.content-script.dev.ts │ ├── rsbuild.content-script.prod.ts │ ├── src │ │ └── contentscript.ts │ └── tsconfig.json ├── inpage │ ├── README.md │ ├── globals.d.ts │ ├── inpage.ts │ ├── jest.config.js │ ├── package.json │ ├── rsbuild.inpage.ts │ ├── src │ │ ├── ChainAgnosticProvider.test.ts │ │ ├── ChainAgnosticProvider.ts │ │ ├── MultiWalletProviderProxy.test.ts │ │ ├── MultiWalletProviderProxy.ts │ │ ├── images │ │ │ └── favicon.svg │ │ ├── index.ts │ │ ├── initializeInpageProvider.test.ts │ │ ├── initializeInpageProvider.ts │ │ ├── models.ts │ │ └── utils │ │ │ ├── ProviderReadyPromise.test.ts │ │ │ ├── ProviderReadyPromise.ts │ │ │ ├── RequestRatelimiter.test.ts │ │ │ ├── RequestRatelimiter.ts │ │ │ ├── getSiteMetadata.test.ts │ │ │ ├── getSiteMetadata.ts │ │ │ ├── onDomReady.test.ts │ │ │ └── onDomReady.ts │ └── tsconfig.json ├── messaging │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── AbstractConnection.test.ts │ │ ├── AbstractConnection.ts │ │ ├── AutoPairingPostMessageConnection.test.ts │ │ ├── AutoPairingPostMessageConnection.ts │ │ ├── PortConnection.test.ts │ │ ├── PortConnection.ts │ │ ├── index.ts │ │ ├── models.ts │ │ └── serialization │ │ │ ├── deserialize.test.ts │ │ │ ├── deserialize.ts │ │ │ ├── index.ts │ │ │ ├── serialize.test.ts │ │ │ └── serialize.ts │ └── tsconfig.json ├── offscreen │ ├── README.md │ ├── package.json │ ├── rsbuild.offscreen.common.ts │ ├── rsbuild.offscreen.dev.ts │ ├── rsbuild.offscreen.prod.ts │ ├── src │ │ ├── offscreen.html │ │ └── offscreen.ts │ └── tsconfig.json ├── service-worker │ ├── README.md │ ├── __mocks__ │ │ └── @blockaid │ │ │ └── client.ts │ ├── jest.config.js │ ├── package.json │ ├── rsbuild.worker.common.ts │ ├── rsbuild.worker.dev.ts │ ├── rsbuild.worker.prod.ts │ ├── src │ │ ├── connections │ │ │ ├── ConnectionService.ts │ │ │ ├── RequestProcessorPipeline.ts │ │ │ ├── dAppConnection │ │ │ │ ├── DAppConnectionController.ts │ │ │ │ └── registry.ts │ │ │ ├── extensionConnection │ │ │ │ ├── DappHandlerToExtensionHandlerTransformer.test.ts │ │ │ │ ├── DappHandlerToExtensionHandlerTransformer.ts │ │ │ │ ├── ExtensionConnectionController.ts │ │ │ │ └── registry.ts │ │ │ ├── middlewares │ │ │ │ ├── ActiveNetworkMiddleware.test.ts │ │ │ │ ├── ActiveNetworkMiddleware.ts │ │ │ │ ├── DAppRequestHandlerMiddleware.ts │ │ │ │ ├── ExtensionRequestHandlerMiddleware.ts │ │ │ │ ├── PermissionMiddleware.ts │ │ │ │ ├── RequestLoggerMiddleware.ts │ │ │ │ ├── SiteMetadataMiddleware.ts │ │ │ │ └── models.ts │ │ │ └── offscreenConnection │ │ │ │ ├── OffscreenConnectionController.ts │ │ │ │ └── registry.ts │ │ ├── index.ts │ │ ├── init.ts │ │ ├── monitoring │ │ │ └── initSentryForBackground.ts │ │ ├── runtime │ │ │ ├── BackgroundRuntime.ts │ │ │ ├── CallbackManager.ts │ │ │ ├── lifecycleCallbacks.ts │ │ │ ├── openApprovalWindow.test.ts │ │ │ └── openApprovalWindow.ts │ │ ├── services │ │ │ ├── accounts │ │ │ │ ├── AccountsService.test.ts │ │ │ │ ├── AccountsService.ts │ │ │ │ ├── events │ │ │ │ │ ├── accountsChangedCAEvent.test.ts │ │ │ │ │ ├── accountsChangedCAEvent.ts │ │ │ │ │ ├── accountsChangedEvent.ts │ │ │ │ │ └── accountsUpdatedEvent.ts │ │ │ │ └── handlers │ │ │ │ │ ├── addAccount.test.ts │ │ │ │ │ ├── addAccount.ts │ │ │ │ │ ├── avalanche_deleteAccounts.test.ts │ │ │ │ │ ├── avalanche_deleteAccounts.ts │ │ │ │ │ ├── avalanche_getAccountPubKey.test.ts │ │ │ │ │ ├── avalanche_getAccountPubKey.ts │ │ │ │ │ ├── avalanche_getAccounts.test.ts │ │ │ │ │ ├── avalanche_getAccounts.ts │ │ │ │ │ ├── avalanche_getAddressesInRange.test.ts │ │ │ │ │ ├── avalanche_getAddressesInRange.ts │ │ │ │ │ ├── avalanche_renameAccount.test.ts │ │ │ │ │ ├── avalanche_renameAccount.ts │ │ │ │ │ ├── avalanche_selectAccount.test.ts │ │ │ │ │ ├── avalanche_selectAccount.ts │ │ │ │ │ ├── eth_accounts.test.ts │ │ │ │ │ ├── eth_accounts.ts │ │ │ │ │ ├── getAccounts.test.ts │ │ │ │ │ ├── getAccounts.ts │ │ │ │ │ ├── getPrivateKey.test.ts │ │ │ │ │ ├── getPrivateKey.ts │ │ │ │ │ ├── selectAccount.test.ts │ │ │ │ │ └── selectAccount.ts │ │ │ ├── actions │ │ │ │ ├── ActionsService.test.ts │ │ │ │ ├── ActionsService.ts │ │ │ │ ├── events │ │ │ │ │ └── actionEvents.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── getActions.ts │ │ │ │ │ ├── updateAction.ts │ │ │ │ │ ├── updateTxData.test.ts │ │ │ │ │ └── updateTxData.ts │ │ │ │ └── utils.ts │ │ │ ├── analytics │ │ │ │ ├── AnalyticsService.ts │ │ │ │ ├── AnalyticsServicePosthog.test.ts │ │ │ │ ├── AnalyticsServicePosthog.ts │ │ │ │ ├── events │ │ │ │ │ └── analyticsStateUpdatedEvent.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── captureAnalyticsEvent.test.ts │ │ │ │ │ ├── captureAnalyticsEvent.ts │ │ │ │ │ ├── clearAnalyticsIds.ts │ │ │ │ │ ├── getAnalyticsIds.ts │ │ │ │ │ ├── initAnalyticsIds.ts │ │ │ │ │ └── storeAnalyticsIds.ts │ │ │ │ └── utils │ │ │ │ │ ├── encryptAnalyticsData.test.ts │ │ │ │ │ ├── encryptAnalyticsData.ts │ │ │ │ │ └── getUserEnvironment.ts │ │ │ ├── appcheck │ │ │ │ ├── AppCheckService.test.ts │ │ │ │ ├── AppCheckService.ts │ │ │ │ └── utils │ │ │ │ │ ├── challenges │ │ │ │ │ ├── basic.test.ts │ │ │ │ │ ├── basic.ts │ │ │ │ │ ├── reverse.test.ts │ │ │ │ │ └── reverse.ts │ │ │ │ │ ├── getHashByAlgorithm.test.ts │ │ │ │ │ ├── getHashByAlgorithm.ts │ │ │ │ │ ├── registerForChallenge.test.ts │ │ │ │ │ ├── registerForChallenge.ts │ │ │ │ │ ├── solveChallenge.test.ts │ │ │ │ │ ├── solveChallenge.ts │ │ │ │ │ ├── verifyChallenge.test.ts │ │ │ │ │ └── verifyChallenge.ts │ │ │ ├── approvals │ │ │ │ ├── ApprovalService.test.ts │ │ │ │ ├── ApprovalService.ts │ │ │ │ └── events │ │ │ │ │ └── approvalEvents.ts │ │ │ ├── balances │ │ │ │ ├── BalanceAggregatorService.test.ts │ │ │ │ ├── BalanceAggregatorService.ts │ │ │ │ ├── BalancePollingService.test.ts │ │ │ │ ├── BalancePollingService.ts │ │ │ │ ├── BalancesService.test.ts │ │ │ │ ├── BalancesService.ts │ │ │ │ ├── TokenPricesService.ts │ │ │ │ ├── events │ │ │ │ │ └── balancesUpdatedEvent.ts │ │ │ │ └── handlers │ │ │ │ │ ├── getBalances.ts │ │ │ │ │ ├── getNativeBalance.ts │ │ │ │ │ ├── getTokenPrice.ts │ │ │ │ │ ├── getTotalBalanceForWallet │ │ │ │ │ ├── getTotalBalanceForWallet.test.ts │ │ │ │ │ ├── getTotalBalanceForWallet.ts │ │ │ │ │ ├── helpers │ │ │ │ │ │ ├── calculateTotalBalanceForAccounts.test.ts │ │ │ │ │ │ ├── calculateTotalBalanceForAccounts.ts │ │ │ │ │ │ ├── getAccountsWithActivity.test.ts │ │ │ │ │ │ ├── getAccountsWithActivity.ts │ │ │ │ │ │ ├── getIncludedNetworks.test.ts │ │ │ │ │ │ ├── getIncludedNetworks.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── isDone.test.ts │ │ │ │ │ │ ├── isDone.ts │ │ │ │ │ │ ├── processGlacierAddresses.test.ts │ │ │ │ │ │ └── processGlacierAddresses.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── models.ts │ │ │ │ │ ├── refreshNftMetadata.test.ts │ │ │ │ │ ├── refreshNftMetadata.ts │ │ │ │ │ ├── startBalancesPolling.test.ts │ │ │ │ │ ├── startBalancesPolling.ts │ │ │ │ │ ├── stopBalancesPolling.test.ts │ │ │ │ │ ├── stopBalancesPolling.ts │ │ │ │ │ └── updateBalancesForNetwork.ts │ │ │ ├── blockaid │ │ │ │ ├── BlockaidService.test.ts │ │ │ │ ├── BlockaidService.ts │ │ │ │ ├── utils.test.ts │ │ │ │ └── utils.ts │ │ │ ├── bridge │ │ │ │ ├── BridgeService.test.ts │ │ │ │ ├── BridgeService.ts │ │ │ │ ├── events │ │ │ │ │ ├── bridgeConfigUpdateEvents.ts │ │ │ │ │ ├── bridgeStateUpdateEvents.ts │ │ │ │ │ ├── bridgeTransferEvents.ts │ │ │ │ │ └── listeners.ts │ │ │ │ ├── fixtures │ │ │ │ │ └── mockBridgeConfig.ts │ │ │ │ └── handlers │ │ │ │ │ ├── avalanche_getBridgeState.ts │ │ │ │ │ ├── createBridgeTransaction.ts │ │ │ │ │ ├── estimateGasForBridgeTx.test.ts │ │ │ │ │ ├── estimateGasForBridgeTx.ts │ │ │ │ │ ├── getBridgeConfig.ts │ │ │ │ │ ├── getBridgeState.ts │ │ │ │ │ ├── removeBridgeTransaction.ts │ │ │ │ │ └── setIsDevEnv.ts │ │ │ ├── contacts │ │ │ │ ├── ContactsService.ts │ │ │ │ ├── events │ │ │ │ │ └── contactsUpdatedEvent.ts │ │ │ │ └── handlers │ │ │ │ │ ├── avalanche_createContact.ts │ │ │ │ │ ├── avalanche_getContacts.ts │ │ │ │ │ ├── avalanche_removeContact.ts │ │ │ │ │ ├── avalanche_updateContact.ts │ │ │ │ │ ├── createContact.ts │ │ │ │ │ ├── getContacts.ts │ │ │ │ │ ├── removeContact.ts │ │ │ │ │ └── updateContact.ts │ │ │ ├── currency │ │ │ │ ├── CurrencyService.test.ts │ │ │ │ ├── CurrencyService.ts │ │ │ │ ├── events │ │ │ │ │ └── currencyRatesUpdatedEvent.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── getCurrencyExchangeRates.test.ts │ │ │ │ │ └── getCurrencyExchangeRates.ts │ │ │ │ └── index.ts │ │ │ ├── debank │ │ │ │ ├── DebankService.test.ts │ │ │ │ ├── DebankService.ts │ │ │ │ ├── fixtures │ │ │ │ │ ├── chain_list.json │ │ │ │ │ ├── explain_tx.json │ │ │ │ │ ├── pre_exec_tx.json │ │ │ │ │ └── user_all_complex_protocol_list.json │ │ │ │ ├── index.ts │ │ │ │ └── utils │ │ │ │ │ ├── debankActionsToTransactionActions.ts │ │ │ │ │ ├── mapNftToTransactionNft.ts │ │ │ │ │ ├── mapTokenItemToTransactionToken.ts │ │ │ │ │ └── txParamsToTransactionData.ts │ │ │ ├── defi │ │ │ │ ├── DefiService.test.ts │ │ │ │ ├── DefiService.ts │ │ │ │ ├── events │ │ │ │ │ └── defiPortfolioUpdatedEvent.ts │ │ │ │ └── handlers │ │ │ │ │ ├── getDefiPortfolio.test.ts │ │ │ │ │ └── getDefiPortfolio.ts │ │ │ ├── featureFlags │ │ │ │ ├── FeatureFlagService.test.ts │ │ │ │ ├── FeatureFlagService.ts │ │ │ │ ├── events │ │ │ │ │ └── featureFlagsUpdatedEvent.ts │ │ │ │ ├── handlers │ │ │ │ │ └── getFeatureFlags.ts │ │ │ │ └── utils │ │ │ │ │ ├── getFeatureFlags.test.ts │ │ │ │ │ └── getFeatureFlags.ts │ │ │ ├── firebase │ │ │ │ ├── FirebaseService.test.ts │ │ │ │ ├── FirebaseService.ts │ │ │ │ └── handlers │ │ │ │ │ ├── sendMessage.ts │ │ │ │ │ └── setModel.ts │ │ │ ├── fireblocks │ │ │ │ ├── FireblocksBTCSigner.test.ts │ │ │ │ ├── FireblocksBTCSigner.ts │ │ │ │ ├── FireblocksSecretsService.ts │ │ │ │ ├── FireblocksService.test.ts │ │ │ │ ├── FireblocksService.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── fireblocksUpdateApiCredentials.test.ts │ │ │ │ │ └── fireblocksUpdateApiCredentials.ts │ │ │ │ ├── models.ts │ │ │ │ └── registry.ts │ │ │ ├── gasless │ │ │ │ ├── GasStationService.test.ts │ │ │ │ ├── GasStationService.ts │ │ │ │ ├── events │ │ │ │ │ ├── gaslessChallangeUpdateEvent.ts │ │ │ │ │ └── gaslessSendMessageEvent.ts │ │ │ │ └── handlers │ │ │ │ │ ├── fetchAndSolveChallenge.test.ts │ │ │ │ │ ├── fetchAndSolveChallenge.ts │ │ │ │ │ ├── fundTx.test.ts │ │ │ │ │ ├── fundTx.ts │ │ │ │ │ ├── getGaslessEligibility.test.ts │ │ │ │ │ ├── getGaslessEligibility.ts │ │ │ │ │ ├── setDefaultStateValues.test.ts │ │ │ │ │ ├── setDefaultStateValues.ts │ │ │ │ │ ├── setHexValues.test.ts │ │ │ │ │ └── setHexValues.ts │ │ │ ├── glacier │ │ │ │ ├── GlacierService.test.ts │ │ │ │ ├── GlacierService.ts │ │ │ │ └── glacierConfig.ts │ │ │ ├── history │ │ │ │ ├── HistoryService.test.ts │ │ │ │ ├── HistoryService.ts │ │ │ │ └── handlers │ │ │ │ │ └── getHistory.ts │ │ │ ├── keystone │ │ │ │ ├── BitcoinKeystoneWallet.test.ts │ │ │ │ ├── BitcoinKeystoneWallet.ts │ │ │ │ ├── KeystoneService.test.ts │ │ │ │ ├── KeystoneService.ts │ │ │ │ ├── KeystoneWallet.test.ts │ │ │ │ ├── KeystoneWallet.ts │ │ │ │ ├── events │ │ │ │ │ └── keystoneDeviceRequest.ts │ │ │ │ ├── handlers │ │ │ │ │ └── keystoneSubmitSignature.ts │ │ │ │ └── utils.ts │ │ │ ├── ledger │ │ │ │ ├── LedgerService.test.ts │ │ │ │ ├── LedgerService.ts │ │ │ │ ├── LedgerTransport.test.ts │ │ │ │ ├── LedgerTransport.ts │ │ │ │ ├── events │ │ │ │ │ ├── ledgerCloseTransport.ts │ │ │ │ │ ├── ledgerDeviceRequest.ts │ │ │ │ │ └── ledgerDiscoverTransports.ts │ │ │ │ └── handlers │ │ │ │ │ ├── closeOpenTransporters.test.ts │ │ │ │ │ ├── closeOpenTransporters.ts │ │ │ │ │ ├── getLedgerVersionWarning.test.ts │ │ │ │ │ ├── getLedgerVersionWarning.ts │ │ │ │ │ ├── initLedgerTransport.test.ts │ │ │ │ │ ├── initLedgerTransport.ts │ │ │ │ │ ├── ledgerResponse.test.ts │ │ │ │ │ ├── ledgerResponse.ts │ │ │ │ │ ├── migrateMissingPublicKeysFromLedger.test.ts │ │ │ │ │ ├── migrateMissingPublicKeysFromLedger.ts │ │ │ │ │ ├── removeLedgerTransport.test.ts │ │ │ │ │ ├── removeLedgerTransport.ts │ │ │ │ │ ├── setLedgerVersionWarningClosed.test.ts │ │ │ │ │ └── setLedgerVersionWarningClosed.ts │ │ │ ├── lock │ │ │ │ ├── LockService.ts │ │ │ │ ├── events │ │ │ │ │ └── lockStateChangedEvent.ts │ │ │ │ └── handlers │ │ │ │ │ ├── changeWalletPassword.ts │ │ │ │ │ ├── getLockState.ts │ │ │ │ │ ├── lockWallet.ts │ │ │ │ │ └── unlockWalletState.ts │ │ │ ├── messages │ │ │ │ ├── handlers │ │ │ │ │ ├── avalanche_signMessage.test.ts │ │ │ │ │ ├── avalanche_signMessage.ts │ │ │ │ │ ├── personal_ecRecover.ts │ │ │ │ │ ├── signMessage.test.ts │ │ │ │ │ └── signMessage.ts │ │ │ │ └── utils │ │ │ │ │ ├── messageParamsParser.test.ts │ │ │ │ │ ├── messageParamsParser.ts │ │ │ │ │ └── personalSigRecovery.ts │ │ │ ├── navigationHistory │ │ │ │ ├── NavigationHistoryService.ts │ │ │ │ └── handlers │ │ │ │ │ ├── getNavigationHistory.ts │ │ │ │ │ ├── getNavigationHistoryData.ts │ │ │ │ │ ├── setNavigationHistory.ts │ │ │ │ │ └── setNavigationHistoryData.ts │ │ │ ├── network │ │ │ │ ├── NetworkService.test.ts │ │ │ │ ├── NetworkService.ts │ │ │ │ ├── events │ │ │ │ │ ├── chainChangedEvent.test.ts │ │ │ │ │ ├── chainChangedEvent.ts │ │ │ │ │ ├── developerModeChangedEvent.ts │ │ │ │ │ ├── networkUpdatedEvent.ts │ │ │ │ │ └── networksUpdatedEvent.ts │ │ │ │ └── handlers │ │ │ │ │ ├── addFavoriteNetwork.ts │ │ │ │ │ ├── avalanche_setDeveloperMode.ts │ │ │ │ │ ├── getNetworkState.ts │ │ │ │ │ ├── removeCustomNetwork.ts │ │ │ │ │ ├── removeFavoriteNetwork.ts │ │ │ │ │ ├── saveCustomNetwork.ts │ │ │ │ │ ├── setActiveNetwork.ts │ │ │ │ │ ├── setDeveloperMode.ts │ │ │ │ │ ├── updateDefaultNetwork.test.ts │ │ │ │ │ ├── updateDefaultNetwork.ts │ │ │ │ │ ├── wallet_addEthereumChain.test.ts │ │ │ │ │ ├── wallet_addEthereumChain.ts │ │ │ │ │ ├── wallet_addNetwork.test.ts │ │ │ │ │ ├── wallet_addNetwork.ts │ │ │ │ │ ├── wallet_getEthereumChain.test.ts │ │ │ │ │ ├── wallet_getEthereumChain.ts │ │ │ │ │ ├── wallet_switchEthereumChain.test.ts │ │ │ │ │ └── wallet_switchEthereumChain.ts │ │ │ ├── networkFee │ │ │ │ ├── NetworkFeeService.test.ts │ │ │ │ ├── NetworkFeeService.ts │ │ │ │ └── handlers │ │ │ │ │ └── getNetworkFee.ts │ │ │ ├── notifications │ │ │ │ ├── BalanceNotificationService.test.ts │ │ │ │ ├── BalanceNotificationService.ts │ │ │ │ ├── NewsNotificationService.test.ts │ │ │ │ ├── NewsNotificationService.ts │ │ │ │ ├── NotificationsService.test.ts │ │ │ │ ├── NotificationsService.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── events │ │ │ │ │ └── subscriptionsChangedEvent.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── getSubscriptions.test.ts │ │ │ │ │ ├── getSubscriptions.ts │ │ │ │ │ ├── subscribe.test.ts │ │ │ │ │ ├── subscribe.ts │ │ │ │ │ ├── unsubscribe.test.ts │ │ │ │ │ └── unsubscribe.ts │ │ │ │ └── utils │ │ │ │ │ ├── getNotificationCategory.test.ts │ │ │ │ │ ├── getNotificationCategory.ts │ │ │ │ │ ├── sendNotification.test.ts │ │ │ │ │ ├── sendNotification.ts │ │ │ │ │ ├── sendRequest.test.ts │ │ │ │ │ └── sendRequest.ts │ │ │ ├── onboarding │ │ │ │ ├── OnboardingService.ts │ │ │ │ ├── events │ │ │ │ │ └── onboardingUpdatedEvent.ts │ │ │ │ ├── finalizeOnboarding.test.ts │ │ │ │ ├── finalizeOnboarding.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── getIsOnBoarded.ts │ │ │ │ │ ├── keystoneOnboardingHandler.test.ts │ │ │ │ │ ├── keystoneOnboardingHandler.ts │ │ │ │ │ ├── ledgerOnboardingHandler.test.ts │ │ │ │ │ ├── ledgerOnboardingHandler.ts │ │ │ │ │ ├── mnemonicOnboardingHandler.test.ts │ │ │ │ │ ├── mnemonicOnboardingHandler.ts │ │ │ │ │ ├── seedlessOnboardingHandler.test.ts │ │ │ │ │ └── seedlessOnboardingHandler.ts │ │ │ │ ├── startOnboarding.test.ts │ │ │ │ ├── startOnboarding.ts │ │ │ │ └── utils │ │ │ │ │ ├── addChainsToFavoriteIfNeeded.test.ts │ │ │ │ │ └── addChainsToFavoriteIfNeeded.ts │ │ │ ├── permissions │ │ │ │ ├── PermissionsService.test.ts │ │ │ │ ├── PermissionsService.ts │ │ │ │ ├── events │ │ │ │ │ └── permissionsStateUpdates.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── getAllPermissions.ts │ │ │ │ │ ├── getPermissionsForDomain.ts │ │ │ │ │ ├── revokeAddressPermissionsForDomain.ts │ │ │ │ │ ├── wallet_getPermissions.ts │ │ │ │ │ ├── wallet_requestPermissions.test.ts │ │ │ │ │ └── wallet_requestPermissions.ts │ │ │ │ └── utils │ │ │ │ │ ├── getPermissionsConvertedToMetaMaskStructure.test.ts │ │ │ │ │ └── getPermissionsConvertedToMetaMaskStructure.ts │ │ │ ├── secrets │ │ │ │ ├── AddressPublicKey.test.ts │ │ │ │ ├── AddressPublicKey.ts │ │ │ │ ├── AddressResolver.test.ts │ │ │ │ ├── AddressResolver.ts │ │ │ │ ├── SecretsService.test.ts │ │ │ │ ├── SecretsService.ts │ │ │ │ ├── events │ │ │ │ │ └── WalletUpdatedEvent.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── appendSolanaPublicKeys.test.ts │ │ │ │ │ ├── appendSolanaPublicKeys.ts │ │ │ │ │ ├── avalanche_renameWallet.test.ts │ │ │ │ │ └── avalanche_renameWallet.ts │ │ │ │ ├── utils.ts │ │ │ │ └── utils │ │ │ │ │ ├── getAccountPrivateKeyFromMnemonic.test.ts │ │ │ │ │ ├── getAccountPrivateKeyFromMnemonic.ts │ │ │ │ │ ├── getAddressForHvm.test.ts │ │ │ │ │ └── getAddressForHvm.ts │ │ │ ├── seedless │ │ │ │ ├── SeedlessBtcSigner.test.ts │ │ │ │ ├── SeedlessBtcSigner.ts │ │ │ │ ├── SeedlessMfaService.test.ts │ │ │ │ ├── SeedlessMfaService.ts │ │ │ │ ├── SeedlessSessionManager.test.ts │ │ │ │ ├── SeedlessSessionManager.ts │ │ │ │ ├── SeedlessTokenStorage.ts │ │ │ │ ├── SeedlessWallet.test.ts │ │ │ │ ├── SeedlessWallet.ts │ │ │ │ ├── events │ │ │ │ │ ├── seedlessMfaEvents.ts │ │ │ │ │ └── seedlessTokenEvents.ts │ │ │ │ ├── fixtures │ │ │ │ │ └── rawKeys.ts │ │ │ │ └── handlers │ │ │ │ │ ├── addFidoDevice.test.ts │ │ │ │ │ ├── addFidoDevice.ts │ │ │ │ │ ├── cancelRecoveryPhraseExport.test.ts │ │ │ │ │ ├── cancelRecoveryPhraseExport.ts │ │ │ │ │ ├── chooseMfaMethod.test.ts │ │ │ │ │ ├── chooseMfaMethod.ts │ │ │ │ │ ├── completeAuthenticatorChange.test.ts │ │ │ │ │ ├── completeAuthenticatorChange.ts │ │ │ │ │ ├── completeRecoveryPhraseExport.test.ts │ │ │ │ │ ├── completeRecoveryPhraseExport.ts │ │ │ │ │ ├── deriveMissingKeys.ts │ │ │ │ │ ├── getRecoveryMethods.test.ts │ │ │ │ │ ├── getRecoveryMethods.ts │ │ │ │ │ ├── getRecoveryPhraseExportState.test.ts │ │ │ │ │ ├── getRecoveryPhraseExportState.ts │ │ │ │ │ ├── hasSignerTokenExpired.test.ts │ │ │ │ │ ├── hasSignerTokenExpired.ts │ │ │ │ │ ├── initAuthenticatorChange.test.ts │ │ │ │ │ ├── initAuthenticatorChange.ts │ │ │ │ │ ├── initRecoveryPhraseExport.test.ts │ │ │ │ │ ├── initRecoveryPhraseExport.ts │ │ │ │ │ ├── removeFidoDevice.test.ts │ │ │ │ │ ├── removeFidoDevice.ts │ │ │ │ │ ├── removeTotp.test.ts │ │ │ │ │ ├── removeTotp.ts │ │ │ │ │ ├── submitMfaResponse.test.ts │ │ │ │ │ ├── submitMfaResponse.ts │ │ │ │ │ ├── updateSignerToken.test.ts │ │ │ │ │ └── updateSignerToken.ts │ │ │ ├── settings │ │ │ │ ├── SettingService.test.ts │ │ │ │ ├── SettingsService.ts │ │ │ │ ├── events │ │ │ │ │ ├── settingsUpdatedEvent.ts │ │ │ │ │ └── wallet_watchAsset.ts │ │ │ │ └── handlers │ │ │ │ │ ├── addCustomToken.ts │ │ │ │ │ ├── getSettings.ts │ │ │ │ │ ├── getTokenDataByAddress.ts │ │ │ │ │ ├── setAnalyticsConsent.ts │ │ │ │ │ ├── setCoreAssistant.ts │ │ │ │ │ ├── setLanguage.ts │ │ │ │ │ ├── updateCollectiblesVisibility.ts │ │ │ │ │ ├── updateCurrencySelection.ts │ │ │ │ │ ├── updateShowTokensNoBalance.ts │ │ │ │ │ ├── updateTheme.ts │ │ │ │ │ └── updateTokensVisibility.ts │ │ │ ├── storage │ │ │ │ ├── StorageService.test.ts │ │ │ │ ├── StorageService.ts │ │ │ │ ├── handlers │ │ │ │ │ └── resetExtensionState.ts │ │ │ │ ├── schemaMigrations │ │ │ │ │ ├── migrations │ │ │ │ │ │ ├── accounts_v2.test.ts │ │ │ │ │ │ ├── accounts_v2.ts │ │ │ │ │ │ ├── accounts_v3.test.ts │ │ │ │ │ │ ├── accounts_v3.ts │ │ │ │ │ │ ├── balances_v2.test.ts │ │ │ │ │ │ ├── balances_v2.ts │ │ │ │ │ │ ├── balances_v3.test.ts │ │ │ │ │ │ ├── balances_v3.ts │ │ │ │ │ │ ├── network_v2.test.ts │ │ │ │ │ │ ├── network_v2.ts │ │ │ │ │ │ ├── network_v3.test.ts │ │ │ │ │ │ ├── network_v3.ts │ │ │ │ │ │ ├── network_v4.ts │ │ │ │ │ │ ├── permissions_v2.test.ts │ │ │ │ │ │ ├── permissions_v2.ts │ │ │ │ │ │ ├── settings_v2.test.ts │ │ │ │ │ │ ├── settings_v2.ts │ │ │ │ │ │ ├── unified_bridge_v2.test.ts │ │ │ │ │ │ ├── unified_bridge_v2.ts │ │ │ │ │ │ ├── wallet_storage_encryption_key_v2.test.ts │ │ │ │ │ │ ├── wallet_storage_encryption_key_v2.ts │ │ │ │ │ │ ├── wallet_v2.test.ts │ │ │ │ │ │ ├── wallet_v2.ts │ │ │ │ │ │ ├── wallet_v3.test.ts │ │ │ │ │ │ ├── wallet_v3.ts │ │ │ │ │ │ ├── wallet_v4 │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── utils │ │ │ │ │ │ │ │ ├── getSecretsType.test.ts │ │ │ │ │ │ │ │ └── getSecretsType.ts │ │ │ │ │ │ │ ├── wallet_v4.test.ts │ │ │ │ │ │ │ └── wallet_v4.ts │ │ │ │ │ │ ├── wallet_v5 │ │ │ │ │ │ │ ├── commonModels.ts │ │ │ │ │ │ │ ├── commonSchemas.ts │ │ │ │ │ │ │ ├── legacyModels.ts │ │ │ │ │ │ │ ├── legacySchema.ts │ │ │ │ │ │ │ ├── newModels.ts │ │ │ │ │ │ │ ├── newSchema.ts │ │ │ │ │ │ │ ├── wallet_v5.test.ts │ │ │ │ │ │ │ └── wallet_v5.ts │ │ │ │ │ │ └── wallet_v6 │ │ │ │ │ │ │ ├── wallet_v6.test.ts │ │ │ │ │ │ │ ├── wallet_v6.ts │ │ │ │ │ │ │ └── wallet_v6_schema.ts │ │ │ │ │ ├── models.ts │ │ │ │ │ ├── schemaMap.ts │ │ │ │ │ ├── schemaMigrations.test.ts │ │ │ │ │ └── schemaMigrations.ts │ │ │ │ └── utils │ │ │ │ │ ├── crypto.e2e.test.ts │ │ │ │ │ ├── crypto.test.ts │ │ │ │ │ └── crypto.ts │ │ │ ├── tokens │ │ │ │ ├── TokenManagerService.ts │ │ │ │ ├── handlers │ │ │ │ │ └── getTokenList.ts │ │ │ │ └── utils │ │ │ │ │ └── isTokenSupported.ts │ │ │ ├── unifiedBridge │ │ │ │ ├── UnifiedBridgeService.test.ts │ │ │ │ ├── UnifiedBridgeService.ts │ │ │ │ ├── events │ │ │ │ │ └── unifiedBridgeEvents.ts │ │ │ │ └── handlers │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── unifiedBridgeGetState.test.ts │ │ │ │ │ ├── unifiedBridgeGetState.ts │ │ │ │ │ └── unifiedBridgeTrackTransfer.ts │ │ │ ├── wallet │ │ │ │ ├── HVMWallet.test.ts │ │ │ │ ├── HVMWallet.ts │ │ │ │ ├── WalletService.test.ts │ │ │ │ ├── WalletService.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── avalanche_sendTransaction.test.ts │ │ │ │ │ ├── avalanche_sendTransaction.ts │ │ │ │ │ ├── avalanche_signTransaction.test.ts │ │ │ │ │ ├── avalanche_signTransaction.ts │ │ │ │ │ ├── getBtcWalletPolicyDetails.test.ts │ │ │ │ │ ├── getBtcWalletPolicyDetails.ts │ │ │ │ │ ├── getUnencryptedMnemonic.test.ts │ │ │ │ │ ├── getUnencryptedMnemonic.ts │ │ │ │ │ ├── getWalletDetails.test.ts │ │ │ │ │ ├── getWalletDetails.ts │ │ │ │ │ ├── importLedger.test.ts │ │ │ │ │ ├── importLedger.ts │ │ │ │ │ ├── importSeedPhrase.test.ts │ │ │ │ │ ├── importSeedPhrase.ts │ │ │ │ │ ├── storeBtcWalletPolicyDetails.test.ts │ │ │ │ │ └── storeBtcWalletPolicyDetails.ts │ │ │ │ └── utils │ │ │ │ │ ├── ensureMessageFormatIsValid.test.ts │ │ │ │ │ ├── ensureMessageFormatIsValid.ts │ │ │ │ │ ├── getAddressByVM.test.ts │ │ │ │ │ ├── getAddressByVM.ts │ │ │ │ │ ├── getDerivationPath.test.ts │ │ │ │ │ ├── getDerivationPath.ts │ │ │ │ │ ├── getProvidedUtxos.test.ts │ │ │ │ │ ├── getProvidedUtxos.ts │ │ │ │ │ ├── getTargetNetworkForTx.test.ts │ │ │ │ │ ├── getTargetNetworkForTx.ts │ │ │ │ │ └── prepareBtcTxForLedger.ts │ │ │ ├── walletConnect │ │ │ │ ├── WalletConnectService.test.ts │ │ │ │ ├── WalletConnectService.ts │ │ │ │ ├── WalletConnectSigner.test.ts │ │ │ │ ├── WalletConnectSigner.ts │ │ │ │ ├── WalletConnectStorage.test.ts │ │ │ │ ├── WalletConnectStorage.ts │ │ │ │ ├── __fixtures__ │ │ │ │ │ └── session.ts │ │ │ │ ├── events │ │ │ │ │ └── walletConnectEvents.ts │ │ │ │ ├── handlers │ │ │ │ │ ├── establishRequiredSession.ts │ │ │ │ │ ├── walletConnectImportAccount.test.ts │ │ │ │ │ └── walletConnectImportAccount.ts │ │ │ │ └── utils.ts │ │ │ └── web3 │ │ │ │ └── handlers │ │ │ │ ├── avalanche_getProviderState.test.ts │ │ │ │ ├── avalanche_getProviderState.ts │ │ │ │ ├── avalanche_selectWallet.ts │ │ │ │ ├── avalanche_sendDomainMetadata.test.ts │ │ │ │ ├── avalanche_sendDomainMetadata.ts │ │ │ │ ├── connect.test.ts │ │ │ │ ├── connect.ts │ │ │ │ ├── wallet_requestAccountPermission.test.ts │ │ │ │ └── wallet_requestAccountPermission.ts │ │ └── vmModules │ │ │ ├── ApprovalController.test.ts │ │ │ ├── ApprovalController.ts │ │ │ ├── ModuleManager.test.ts │ │ │ ├── ModuleManager.ts │ │ │ └── models.ts │ └── tsconfig.json ├── tsconfig │ ├── package.json │ └── tsconfig.base.json ├── types │ ├── README.md │ ├── images.d.ts │ ├── package.json │ ├── src │ │ ├── account.ts │ │ ├── actions.ts │ │ ├── analytics.ts │ │ ├── app-check.ts │ │ ├── approvals.ts │ │ ├── balance.ts │ │ ├── bridge.ts │ │ ├── contacts.ts │ │ ├── currency.ts │ │ ├── dapp-connection.ts │ │ ├── debank.ts │ │ ├── defi.ts │ │ ├── domain-metadata.ts │ │ ├── error.ts │ │ ├── feature-flags.ts │ │ ├── firebase.ts │ │ ├── fireblocks.ts │ │ ├── gasless.ts │ │ ├── history.ts │ │ ├── index.ts │ │ ├── keystone.ts │ │ ├── keystore.ts │ │ ├── ledger.ts │ │ ├── lock.ts │ │ ├── messages.ts │ │ ├── navigation-history.ts │ │ ├── network-fee.ts │ │ ├── network.ts │ │ ├── notifications.ts │ │ ├── onboarding.ts │ │ ├── permissions.ts │ │ ├── secrets.ts │ │ ├── seedless.ts │ │ ├── send.ts │ │ ├── settings.ts │ │ ├── storage.ts │ │ ├── tokens.ts │ │ ├── transaction.ts │ │ ├── ui-connection.ts │ │ ├── ui.ts │ │ ├── unified-bridge.ts │ │ ├── util-types.ts │ │ ├── wallet-connect.ts │ │ ├── wallet.ts │ │ └── web3.ts │ ├── types.d.ts │ └── webextension-polyfill.d.ts └── ui │ ├── __mocks__ │ └── @blockaid │ │ └── client.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ ├── contexts │ │ ├── AccountManagerProvider.tsx │ │ ├── AccountsProvider │ │ │ ├── AccountsProvider.tsx │ │ │ ├── index.tsx │ │ │ └── isAccountsUpdatedEvent.ts │ │ ├── AnalyticsProvider │ │ │ ├── AnalyticsProvider.test.tsx │ │ │ ├── AnalyticsProvider.tsx │ │ │ ├── index.tsx │ │ │ └── isAnalyticsStateUpdatedEvent.ts │ │ ├── ApprovalsProvider │ │ │ ├── ApprovalsProvider.tsx │ │ │ ├── index.tsx │ │ │ ├── isActionsUpdate.ts │ │ │ └── isApprovalRequest.ts │ │ ├── BalancesProvider │ │ │ ├── BalancesProvider.tsx │ │ │ ├── index.tsx │ │ │ └── isBalancesUpdatedEvent.ts │ │ ├── BridgeProvider.test.tsx │ │ ├── BridgeProvider.tsx │ │ ├── ConnectionProvider.tsx │ │ ├── ContactsProvider │ │ │ ├── ContactsProvider.tsx │ │ │ ├── contactsEventFilters.ts │ │ │ └── index.tsx │ │ ├── CurrenciesProvider │ │ │ ├── CurrenciesProvider.tsx │ │ │ ├── currencyRatesEventFilters.ts │ │ │ └── index.tsx │ │ ├── DefiProvider │ │ │ ├── DefiProvider.tsx │ │ │ ├── defiEventFilters.ts │ │ │ └── index.tsx │ │ ├── FeatureFlagsProvider │ │ │ ├── FeatureFlagsProvider.tsx │ │ │ ├── index.tsx │ │ │ └── isFeatureFlagsUpdatedEvent.ts │ │ ├── FirebaseProvider.tsx │ │ ├── KeystoneProvider.tsx │ │ ├── LedgerProvider │ │ │ ├── LedgerProvider.test.tsx │ │ │ ├── LedgerProvider.tsx │ │ │ ├── index.tsx │ │ │ └── listeners.ts │ │ ├── NetworkFeeProvider │ │ │ ├── NetworkFeeProvider.tsx │ │ │ ├── gaslessChallangeUpdateListener.ts │ │ │ ├── gaslessSendMessageListener.ts │ │ │ └── index.ts │ │ ├── NetworkProvider │ │ │ ├── NetworkProvider.tsx │ │ │ ├── index.tsx │ │ │ ├── isNetworkUpdatedEvent.ts │ │ │ ├── networkChanges.ts │ │ │ └── networksUpdatedEventListener.ts │ │ ├── NotificationsProvider.tsx │ │ ├── OnboardingProvider │ │ │ ├── OnboardingProvider.tsx │ │ │ ├── index.tsx │ │ │ └── listeners.ts │ │ ├── PermissionsProvider │ │ │ ├── PermissionsProvider.tsx │ │ │ ├── index.tsx │ │ │ └── permissionsEventFilters.ts │ │ ├── SeedlessMfaManagementProvider.tsx │ │ ├── SettingsProvider │ │ │ ├── SettingsProvider.tsx │ │ │ ├── index.tsx │ │ │ ├── isSettingsUpdatedEvent.ts │ │ │ └── models.ts │ │ ├── SwapProvider │ │ │ ├── ABI_WAVAX.json │ │ │ ├── ABI_WETH.json │ │ │ ├── SwapProvider.test.tsx │ │ │ ├── SwapProvider.tsx │ │ │ ├── constants.ts │ │ │ ├── index.tsx │ │ │ ├── models.ts │ │ │ ├── schemas.ts │ │ │ ├── swap-utils.test.ts │ │ │ ├── swap-utils.ts │ │ │ ├── useEvmSwap.test.tsx │ │ │ ├── useEvmSwap.tsx │ │ │ ├── useSolanaSwap.test.tsx │ │ │ └── useSolanaSwap.tsx │ │ ├── UnifiedBridgeProvider.test.tsx │ │ ├── UnifiedBridgeProvider.tsx │ │ ├── WalletConnectContextProvider │ │ │ ├── WalletConnectContextProvider.tsx │ │ │ ├── importReducer.ts │ │ │ ├── index.ts │ │ │ └── models.ts │ │ ├── WalletProvider.tsx │ │ ├── WalletTotalBalanceProvider.tsx │ │ ├── index.ts │ │ ├── isSubscriptionsChangedEvent.ts │ │ └── utils │ │ │ ├── connectionResponseMapper.ts │ │ │ ├── getCurrencyFormatter.test.ts │ │ │ ├── getCurrencyFormatter.ts │ │ │ └── getLedgerTransport.ts │ ├── hooks │ │ ├── index.ts │ │ ├── useAnalyticsConsentCallbacks.ts │ │ ├── useAppDimensions.ts │ │ ├── useAppTypeFromParams.ts │ │ ├── useApprovalHelpers.ts │ │ ├── useApproveAction.ts │ │ ├── useBalanceTotalInCurrency.test.ts │ │ ├── useBalanceTotalInCurrency.ts │ │ ├── useBridge.ts │ │ ├── useBridgeAmounts.ts │ │ ├── useBridgeNetworkPrice.ts │ │ ├── useBridgeTransferStatus.ts │ │ ├── useBridgeTxHandling.ts │ │ ├── useCameraPermissions.ts │ │ ├── useCoinGeckoId.test.ts │ │ ├── useCoinGeckoId.ts │ │ ├── useContactIdFromParams.ts │ │ ├── useConvertedCurrencyFormatter.ts │ │ ├── useDAppScan.test.ts │ │ ├── useDAppScan.ts │ │ ├── useDismissedBanners.ts │ │ ├── useDisplayTokenList.ts │ │ ├── useErrorMessage.ts │ │ ├── useFidoErrorMessage.ts │ │ ├── useGetAvaxBalance.ts │ │ ├── useGetRequestId.test.ts │ │ ├── useGetRequestId.ts │ │ ├── useGetSolBalance.ts │ │ ├── useGoBack.ts │ │ ├── useHasEnoughtForGas.ts │ │ ├── useImportLedger.ts │ │ ├── useImportSeedphrase.ts │ │ ├── useInterval.ts │ │ ├── useIsFunctionAvailable.ts │ │ ├── useIsIncorrectDevice.ts │ │ ├── useIsMainnet.ts │ │ ├── useIsSolanaEnabled.ts │ │ ├── useIsSpecificContextContainer.ts │ │ ├── useIsUsingFireblocksAccount.ts │ │ ├── useIsUsingKeystoneWallet.ts │ │ ├── useIsUsingLedgerWallet.test.ts │ │ ├── useIsUsingLedgerWallet.ts │ │ ├── useIsUsingSeedlessAccount.ts │ │ ├── useIsUsingWalletConnectAccount.ts │ │ ├── useJsonFileReader.ts │ │ ├── useKeyboardShortcuts.ts │ │ ├── useKeystoreFileImport.test.ts │ │ ├── useKeystoreFileImport.ts │ │ ├── useLanguages.ts │ │ ├── useLiveBalance.ts │ │ ├── useLocalStorage.ts │ │ ├── useLogoUriForBridgeTransaction.ts │ │ ├── useNfts.ts │ │ ├── useOnline.ts │ │ ├── usePageHistory.ts │ │ ├── usePendingBridgeTransactions.ts │ │ ├── usePersistedTabs.ts │ │ ├── usePrivateKeyExport.ts │ │ ├── usePrivateKeyImport.ts │ │ ├── useQueryParams.ts │ │ ├── useRegisterBtcWalletPolicy.ts │ │ ├── useSeedlessActions.ts │ │ ├── useSeedlessAuth.ts │ │ ├── useSeedlessAuthPromptState.ts │ │ ├── useSeedlessMnemonicExport.ts │ │ ├── useSendAnalyticsData.ts │ │ ├── useSetSendDataInParams.ts │ │ ├── useSolanaAddressInfo.ts │ │ ├── useSolanaPublicKeys.ts │ │ ├── useSyncBridgeConfig.ts │ │ ├── useTabFromParams.ts │ │ ├── useTokenFromParams.ts │ │ ├── useTokenPrice.ts │ │ ├── useTokenPriceIsMissing.ts │ │ ├── useTokensWithBalances.ts │ │ ├── useTotpErrorMessage.ts │ │ ├── useWalletName.ts │ │ ├── useWalletTotalBalance.ts │ │ ├── useWillSwitchToPrimaryAccount.ts │ │ └── useWindowGetsClosedOrHidden.ts │ └── index.ts │ └── tsconfig.json ├── sentryscript.js ├── src ├── inpage.js ├── inpage_dup.ts ├── rsbuild_template_index.html └── tests │ ├── MockTextEncoder.ts │ ├── resolver.js │ ├── setupTests.ts │ └── test-utils.tsx └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | indent_style = tab 7 | indent_size = 2 8 | insert_final_newline = true -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # the repo. Unless a later match takes precedence, 3 | # @ava-labs/wallet team will be requested for 4 | # review when someone opens a pull request. 5 | @ava-labs/wallet 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | 6 | ## Changes 7 | 8 | 9 | 10 | ## Testing 11 | 12 | 13 | 14 | 15 | ## Screenshots: 16 | 17 | 18 | 19 | ## Checklist for the author 20 | 21 | Tick each of them when done or if not applicable. 22 | 23 | - [ ] I've covered new/modified business logic with Jest test cases. 24 | - [ ] I've tested the changes myself before sending it to code review and QA. 25 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit "${1}" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.18.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | /.pnp 4 | .pnp.js 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /dist 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "[html]": { 4 | "editor.formatOnSave": false 5 | }, 6 | "[javascript]": { 7 | "editor.formatOnSave": false 8 | }, 9 | "[javascriptreact]": { 10 | "editor.formatOnSave": false 11 | }, 12 | "[typescript]": { 13 | "editor.formatOnSave": false 14 | }, 15 | "[typescriptreact]": { 16 | "editor.formatOnSave": false 17 | }, 18 | "editor.codeActionsOnSave": { 19 | "source.fixAll.eslint": "explicit" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.yarn/patches/@mui-material-npm-6.4.11-84c49ed24a.patch: -------------------------------------------------------------------------------- 1 | diff --git a/styles/createThemeNoVars.js b/styles/createThemeNoVars.js 2 | index 155988969c4947d85fcde9cb1b55faa266cb12f7..5945487cdd9e7218c36dfe52f7e5daff094d7bcd 100644 3 | --- a/styles/createThemeNoVars.js 4 | +++ b/styles/createThemeNoVars.js 5 | @@ -67,7 +67,7 @@ function createThemeNoVars(options = {}, ...args) { 6 | }; 7 | Object.keys(muiTheme.components).forEach(component => { 8 | const styleOverrides = muiTheme.components[component].styleOverrides; 9 | - if (styleOverrides && component.startsWith('Mui')) { 10 | + if (styleOverrides && typeof styleOverrides !== 'string' &&component.startsWith('Mui')) { 11 | traverse(styleOverrides, component); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | # https://yarnpkg.com/migration/guide#update-your-configuration-to-the-new-settings 4 | # ignore-scripts true -> enableScripts: false 5 | enableScripts: false 6 | -------------------------------------------------------------------------------- /__mocks__/@blockaid/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @blockaid/client runs environment checks on import. 3 | * This results in errors being thrown if it gets incluced anywhere in the dependency tree. 4 | * fetch is not available with the `jest-environment-jsdom` environment. 5 | * To avoid errors, make sure we mock this library everywhere. 6 | */ 7 | 8 | export default {}; 9 | -------------------------------------------------------------------------------- /apps/legacy/README.md: -------------------------------------------------------------------------------- 1 | # ui 2 | -------------------------------------------------------------------------------- /apps/legacy/__mocks__/@blockaid/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @blockaid/client runs environment checks on import. 3 | * This results in errors being thrown if it gets incluced anywhere in the dependency tree. 4 | * fetch is not available with the `jest-environment-jsdom` environment. 5 | * To avoid errors, make sure we mock this library everywhere. 6 | */ 7 | 8 | export default {}; 9 | -------------------------------------------------------------------------------- /apps/legacy/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */ 2 | 3 | module.exports = { 4 | clearMocks: true, 5 | preset: 'ts-jest', 6 | resolver: '/../../src/tests/resolver.js', 7 | testEnvironment: 'jest-environment-jsdom', 8 | setupFilesAfterEnv: ['/../../src/tests/setupTests.ts'], 9 | moduleNameMapper: { 10 | '^@/(.*)': '/src/$1', 11 | '^@shared/(.*)': '/../../src/$1', 12 | '\\.(css|less|scss)$': 'identity-obj-proxy', 13 | '^uuid$': require.resolve('uuid'), 14 | }, 15 | transform: { 16 | '^.+\\.(js|jsx)$': 'babel-jest', 17 | }, 18 | transformIgnorePatterns: [`/node_modules/(?!micro-eth-signer)`], 19 | modulePathIgnorePatterns: ['/dist/'], 20 | }; 21 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/de/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/hi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/ja/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/ko/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/ru/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/tr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/manifest/_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/BalanceColumn.tsx: -------------------------------------------------------------------------------- 1 | import { Stack, styled } from '@avalabs/core-k2-components'; 2 | 3 | export const BalanceColumn = styled(Stack)` 4 | align-items: end; 5 | padding-left: 8px; 6 | line-height: 14px; 7 | `; 8 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/EmptyContent.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@shared/tests/test-utils'; 2 | import { EmptyContent } from './EmptyContent'; 3 | 4 | describe('components/common/EmptyContent', () => { 5 | it('renders', async () => { 6 | render(); 7 | 8 | expect(screen.getByTestId('empty-list-text').textContent).toEqual( 9 | 'Some test text', 10 | ); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/EmptyContent.tsx: -------------------------------------------------------------------------------- 1 | import { Stack, Grow, Typography } from '@avalabs/core-k2-components'; 2 | 3 | interface EmptyContentProps { 4 | text: string; 5 | } 6 | 7 | const commonTransitionProps = { 8 | timeout: 500, 9 | easing: 'ease-in-out', 10 | appear: true, 11 | }; 12 | 13 | export function EmptyContent({ text }: EmptyContentProps) { 14 | return ( 15 | 16 | 24 | 25 | {text} 26 | 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/FlexScrollbars.tsx: -------------------------------------------------------------------------------- 1 | import { Scrollbars, styled } from '@avalabs/core-k2-components'; 2 | 3 | export const FlexScrollbars = styled(Scrollbars)` 4 | flex-grow: 1; 5 | max-height: unset; 6 | height: 100%; 7 | width: 100%; 8 | 9 | & > div { 10 | display: flex; 11 | flex-direction: column; 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/InlineBold.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@avalabs/core-k2-components'; 2 | 3 | export const InlineBold = styled('span')` 4 | font-weight: bold; 5 | `; 6 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/InlineTokenEllipsis.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@avalabs/core-k2-components'; 2 | import { TokenEllipsis } from './TokenEllipsis'; 3 | 4 | export const InlineTokenEllipsis = styled(TokenEllipsis)` 5 | display: inline-block; 6 | `; 7 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/LoadingOverlay.tsx: -------------------------------------------------------------------------------- 1 | import { CircularProgress } from '@avalabs/core-k2-components'; 2 | import { Overlay } from './Overlay'; 3 | 4 | export function LoadingOverlay() { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/SiteAvatar.tsx: -------------------------------------------------------------------------------- 1 | import { Stack, styled } from '@avalabs/core-k2-components'; 2 | 3 | export const SiteAvatar = styled(Stack)<{ margin?: string }>` 4 | width: 80px; 5 | height: 80px; 6 | background-color: ${({ theme }) => theme.palette.background.paper}; 7 | justify-content: center; 8 | align-items: center; 9 | border-radius: 50%; 10 | margin: ${({ margin }) => margin ?? '8px 0'}; 11 | `; 12 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/SolanaLogoIcon.tsx: -------------------------------------------------------------------------------- 1 | import { Box, SxProps } from '@avalabs/core-k2-components'; 2 | 3 | import solanaLogo from '@/images/logos/solana-logo.png'; 4 | 5 | export const SolanaLogoIcon = ({ 6 | size = 16, 7 | sx, 8 | }: { 9 | size?: number; 10 | sx?: SxProps; 11 | }) => { 12 | return ( 13 | 23 | Solana Logo 24 | 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/StyledNumberList.tsx: -------------------------------------------------------------------------------- 1 | import { styled, Typography } from '@avalabs/core-k2-components'; 2 | 3 | export const StyledNumberList = styled(Typography)` 4 | ${({ theme }) => ({ 5 | ...theme.typography.body1, 6 | display: 'block', 7 | backgroundColor: theme.palette.background.paper, 8 | lineHeight: theme.spacing(3), 9 | height: theme.spacing(3), 10 | width: theme.spacing(3), 11 | borderRadius: '50%', 12 | textAlign: 'center', 13 | marginRight: theme.spacing(2), 14 | flexShrink: 0, 15 | })} 16 | `; 17 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/TextFieldLabel.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | InfoCircleIcon, 3 | Stack, 4 | Tooltip, 5 | Typography, 6 | } from '@avalabs/core-k2-components'; 7 | 8 | interface TextFieldLabelProps { 9 | label: string; 10 | tooltip?: string; 11 | } 12 | 13 | export const TextFieldLabel = ({ label, tooltip }: TextFieldLabelProps) => ( 14 | 15 | 16 | {label} 17 | 18 | {tooltip && ( 19 | 20 | 21 | 22 | )} 23 | 24 | ); 25 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/VerticalStack.tsx: -------------------------------------------------------------------------------- 1 | import { Stack, StackProps } from '@avalabs/core-k2-components'; 2 | 3 | export const VerticalStack = (props: Exclude) => ( 4 | 5 | ); 6 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/VirtualizedList.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@avalabs/core-k2-components'; 2 | import { FixedSizeList as List } from 'react-window'; 3 | 4 | const VirtualizedList = styled(List)` 5 | &::-webkit-scrollbar { 6 | width: 6px; 7 | } 8 | &::-webkit-scrollbar-thumb { 9 | background: ${({ theme }) => theme.palette.divider}; 10 | border-radius: 3px; 11 | } 12 | `; 13 | export default VirtualizedList; 14 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/WalletLoading.tsx: -------------------------------------------------------------------------------- 1 | import { useWalletContext } from '@core/ui'; 2 | import { LoadingContent } from '@/popup/LoadingContent'; 3 | import { PropsWithChildren } from 'react'; 4 | 5 | export function WalletLoading({ children }: PropsWithChildren) { 6 | const { isWalletLoading } = useWalletContext(); 7 | 8 | if (isWalletLoading) { 9 | return ; 10 | } 11 | 12 | return children; 13 | } 14 | -------------------------------------------------------------------------------- /apps/legacy/src/components/common/header/NetworkSwitcher/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NetworkSwitcher'; 2 | -------------------------------------------------------------------------------- /apps/legacy/src/components/icons/BeadIcon.tsx: -------------------------------------------------------------------------------- 1 | export function BeadIcon({ 2 | height = '24px', 3 | color, 4 | }: { 5 | color: string; 6 | height: string; 7 | }) { 8 | return ( 9 | 16 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /apps/legacy/src/components/icons/BrandName.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from '@avalabs/core-k2-components'; 2 | 3 | interface BrandNameProps { 4 | height?: number; 5 | width?: number; 6 | margin?: string; 7 | padding?: string; 8 | } 9 | 10 | export function BrandName({ 11 | height, 12 | width, 13 | margin = '0', 14 | padding = '0', 15 | }: BrandNameProps) { 16 | return ( 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /apps/legacy/src/components/icons/CameraAccessDeniedIcon.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | CameraBlockedIcon, 3 | IconBaseProps, 4 | useTheme, 5 | } from '@avalabs/core-k2-components'; 6 | 7 | export default function CameraAccessDeniedIcon(props: IconBaseProps) { 8 | const theme = useTheme(); 9 | 10 | return ( 11 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /apps/legacy/src/components/icons/InvalidQRCodeIcon.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | IconBaseProps, 3 | QRCodeIcon, 4 | useTheme, 5 | } from '@avalabs/core-k2-components'; 6 | 7 | export default function InvalidQRCodeIcon(props: IconBaseProps) { 8 | const theme = useTheme(); 9 | 10 | return ( 11 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /apps/legacy/src/components/settings/components/StyledListItemButton.tsx: -------------------------------------------------------------------------------- 1 | import { ListItemButton, styled } from '@avalabs/core-k2-components'; 2 | 3 | export const StyledListButton = styled(ListItemButton)` 4 | justify-content: space-between; 5 | padding: 10px 16px; 6 | margin: 0; 7 | &:hover { 8 | border-radius: 0; 9 | } 10 | &.Mui-selected { 11 | border-radius: 0; 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /apps/legacy/src/components/settings/models.ts: -------------------------------------------------------------------------------- 1 | import { SettingsPages } from '@core/ui'; 2 | 3 | export interface SettingsPageProps { 4 | width: string; 5 | navigateTo: (page: SettingsPages) => void; 6 | goBack: () => void; 7 | onClose?: () => void; 8 | showNotificationDotOn?: SettingsPages[]; 9 | } 10 | -------------------------------------------------------------------------------- /apps/legacy/src/hooks/useScopedToast.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from 'react'; 2 | import { toast } from '@avalabs/core-k2-components'; 3 | 4 | export const useScopedToast = (id: string) => { 5 | const success = useCallback( 6 | (...[message, opts]: Parameters) => { 7 | toast.dismiss(id); 8 | 9 | return toast.success(message, { ...opts, id: id }); 10 | }, 11 | [id], 12 | ); 13 | 14 | const error = useCallback( 15 | (...[message, opts]: Parameters) => { 16 | toast.dismiss(id); 17 | 18 | return toast.error(message, { ...opts, id: id }); 19 | }, 20 | [id], 21 | ); 22 | 23 | return { 24 | success, 25 | error, 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /apps/legacy/src/images/Core_logo_black_text_white_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/Core_logo_black_text_white_background.png -------------------------------------------------------------------------------- /apps/legacy/src/images/Core_logo_white_text_black_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/Core_logo_white_text_black_background.png -------------------------------------------------------------------------------- /apps/legacy/src/images/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/android-chrome-512x512.png -------------------------------------------------------------------------------- /apps/legacy/src/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/legacy/src/images/beta-logos/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/beta-logos/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/legacy/src/images/beta-logos/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/beta-logos/icon-16.png -------------------------------------------------------------------------------- /apps/legacy/src/images/beta-logos/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/beta-logos/icon-192.png -------------------------------------------------------------------------------- /apps/legacy/src/images/beta-logos/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/beta-logos/icon-256.png -------------------------------------------------------------------------------- /apps/legacy/src/images/beta-logos/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/beta-logos/icon-32.png -------------------------------------------------------------------------------- /apps/legacy/src/images/core-ext-hero-hq.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/core-ext-hero-hq.webm -------------------------------------------------------------------------------- /apps/legacy/src/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/favicon.ico -------------------------------------------------------------------------------- /apps/legacy/src/images/halliday-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/halliday-icon.png -------------------------------------------------------------------------------- /apps/legacy/src/images/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/icon-128.png -------------------------------------------------------------------------------- /apps/legacy/src/images/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/icon-16.png -------------------------------------------------------------------------------- /apps/legacy/src/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/icon-192.png -------------------------------------------------------------------------------- /apps/legacy/src/images/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/icon-32.png -------------------------------------------------------------------------------- /apps/legacy/src/images/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/icon-48.png -------------------------------------------------------------------------------- /apps/legacy/src/images/keystone/keystone_onboarding_step_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/keystone/keystone_onboarding_step_1.png -------------------------------------------------------------------------------- /apps/legacy/src/images/keystone/keystone_onboarding_step_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/keystone/keystone_onboarding_step_2.png -------------------------------------------------------------------------------- /apps/legacy/src/images/keystone/keystone_onboarding_step_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/keystone/keystone_onboarding_step_3.png -------------------------------------------------------------------------------- /apps/legacy/src/images/logos/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/logos/circle.png -------------------------------------------------------------------------------- /apps/legacy/src/images/logos/coinbase.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/legacy/src/images/logos/solana-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/logos/solana-logo.png -------------------------------------------------------------------------------- /apps/legacy/src/images/logos/solana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/logos/solana.png -------------------------------------------------------------------------------- /apps/legacy/src/images/no_image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /apps/legacy/src/images/onboarding-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/onboarding-background.png -------------------------------------------------------------------------------- /apps/legacy/src/images/tokens/eth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/legacy/src/images/tokens/eth.png -------------------------------------------------------------------------------- /apps/legacy/src/localization/externalPhrases.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file should contain any translations that are present directly in our code. 3 | * E.g. if you want to add strings that are returned by APIs, they would not be caught 4 | * by i18next scanner. 5 | */ 6 | 7 | import { t } from 'i18next'; 8 | 9 | // ---- DeBank API ---- 10 | t('Deposit'); 11 | t('Farming'); 12 | t('Governance'); 13 | t('Insurance Buyer'); 14 | t('Investment'); 15 | t('Lending'); 16 | t('Liquidity Pool'); 17 | t('Locked'); 18 | t('Perpetuals'); 19 | t('Rewards'); 20 | t('Staked'); 21 | t('TokenSets'); 22 | t('Vesting'); 23 | t('Yield'); 24 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Bridge/components/BridgeCard.tsx: -------------------------------------------------------------------------------- 1 | import { Card, CardProps, useTheme } from '@avalabs/core-k2-components'; 2 | 3 | type BridgeCardProps = CardProps & { 4 | isWaiting: boolean; 5 | isDone: boolean; 6 | isTransferComplete: boolean; 7 | }; 8 | export const BridgeCard = ({ 9 | isWaiting, 10 | isDone, 11 | isTransferComplete, 12 | ...props 13 | }: BridgeCardProps) => { 14 | const theme = useTheme(); 15 | 16 | return ( 17 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Collectibles/components/CollectibleListEmpty.tsx: -------------------------------------------------------------------------------- 1 | import { Typography, Stack } from '@avalabs/core-k2-components'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | export function CollectibleListEmpty() { 5 | const { t } = useTranslation(); 6 | return ( 7 | 15 | {t('No Collectibles')} 16 | 17 | {t('You don’t have any NFTs yet!')} 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Collectibles/components/CollectibleSkeleton.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from '@avalabs/core-k2-components'; 2 | import { CollectibleWrapper } from './CollectibleWrapper'; 3 | 4 | export function CollectibleSkeleton() { 5 | return ( 6 | 7 | {Array.from({ length: 4 }, (_: unknown, i: number) => ( 8 | 17 | ))}{' '} 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/DeFi/components/DefiErrorState.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | import { 3 | AlertCircleIcon, 4 | Stack, 5 | StackProps, 6 | Typography, 7 | } from '@avalabs/core-k2-components'; 8 | 9 | export const DefiErrorState = (props: StackProps) => { 10 | const { t } = useTranslation(); 11 | 12 | return ( 13 | 14 | 15 | {t('Error!')} 16 | 17 | {t('Data currently unavailable, check back later.')} 18 | 19 | 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Home/Home.tsx: -------------------------------------------------------------------------------- 1 | import { Portfolio } from './components/Portfolio/Portfolio'; 2 | import { LedgerWrongVersionOverlay } from '../Ledger/LedgerWrongVersionOverlay'; 3 | import { Stack } from '@avalabs/core-k2-components'; 4 | 5 | export function Home() { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Home/components/Portfolio/NetworkWidget/common/NetworkCard.tsx: -------------------------------------------------------------------------------- 1 | import { Card, styled } from '@avalabs/core-k2-components'; 2 | 3 | export const NetworkCard = styled(Card)` 4 | padding: 16px; 5 | cursor: pointer; 6 | line-height: 1; 7 | &:hover { 8 | background-color: ${({ theme }) => `${theme.palette.grey[800]}b3`}; 9 | } 10 | `; 11 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/ImportWithWalletConnect/components/WalletConnectCircledIcon.tsx: -------------------------------------------------------------------------------- 1 | import { WalletConnectIcon, Avatar } from '@avalabs/core-k2-components'; 2 | 3 | export const WalletConnectCircledIcon = () => ( 4 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/ImportWithWalletConnect/components/utils/getColorForStatus.ts: -------------------------------------------------------------------------------- 1 | import { AccountImportStatus } from '@core/ui'; 2 | 3 | export const getColorForStatus = (status: AccountImportStatus) => { 4 | switch (status) { 5 | case AccountImportStatus.Failed: 6 | return 'error.main'; 7 | 8 | case AccountImportStatus.Successful: 9 | return 'success.main'; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/ImportWithWalletConnect/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ImportWithWalletConnect'; 2 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Ledger/models.ts: -------------------------------------------------------------------------------- 1 | export type DerivationStatus = 'waiting' | 'ready'; 2 | 3 | export type DerivedAddressInfo = { 4 | address: string; 5 | balance: string; 6 | explorerLink: string; 7 | }; 8 | 9 | export type SolanaPublicKey = { 10 | index: number; 11 | key: string; 12 | }; 13 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Networks/common/NetworkListItem.ts: -------------------------------------------------------------------------------- 1 | import { Stack, styled } from '@avalabs/core-k2-components'; 2 | 3 | export const NetworkListItem = styled(Stack, { 4 | shouldForwardProp: (prop) => prop !== 'isActive', 5 | })<{ 6 | isActive?: boolean; 7 | }>` 8 | flex-direction: row; 9 | align-items: center; 10 | justify-content: space-between; 11 | padding: 16px; 12 | cursor: pointer; 13 | width: 100%; 14 | transition: background-color 0.15s ease-in-out; 15 | background-color: ${({ isActive, theme }) => 16 | isActive ? `${theme.palette.grey[900]}80` : 'inherit'}; 17 | 18 | :hover { 19 | background-color: ${({ theme }) => `${theme.palette.grey[900]}80`}; 20 | } 21 | `; 22 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Networks/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Networks'; 2 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Onboarding/components/TypographyLink.tsx: -------------------------------------------------------------------------------- 1 | import { styled, Typography } from '@avalabs/core-k2-components'; 2 | 3 | export const TypographyLink = styled(Typography)` 4 | cursor: pointer; 5 | color: ${({ theme }) => theme.palette.secondary.main}; 6 | font-weight: 600; 7 | text-decoration: none; 8 | `; 9 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Onboarding/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Onboarding'; 2 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Onboarding/pages/CreateWallet/Mnemonic.tsx: -------------------------------------------------------------------------------- 1 | import { ConfirmMnemonic } from './ConfirmMnemonic'; 2 | import { ShowMnemonic } from './ShowMnemonic'; 3 | 4 | export interface MnemonicProps { 5 | phrase: string; 6 | wordCount?: number; 7 | confirmWordCount?: number; 8 | confirmMnemonic?: boolean; 9 | onConfirmedChange?: (confirmed: boolean) => void; 10 | } 11 | 12 | export function Mnemonic(props: MnemonicProps) { 13 | return props.confirmMnemonic ? ( 14 | 15 | ) : ( 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Onboarding/pages/Welcome/Welcome.tsx: -------------------------------------------------------------------------------- 1 | import { SignUpWithSeedless } from './SignUpWithSeedless'; 2 | import { Stack } from '@avalabs/core-k2-components'; 3 | import { useOnboardingContext } from '@core/ui'; 4 | import { useEffect } from 'react'; 5 | 6 | export function Welcome() { 7 | const { resetStates } = useOnboardingContext(); 8 | 9 | useEffect(() => { 10 | resetStates(); 11 | }, [resetStates]); 12 | 13 | return ( 14 | 15 | 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Onboarding/utils/getRandomMnemonicWord.ts: -------------------------------------------------------------------------------- 1 | import { wordlists } from 'bip39'; 2 | 3 | export const getRandomMnemonicWord = (wordlist = 'english'): string => { 4 | const words = wordlists[wordlist]; 5 | 6 | if (!words) { 7 | throw new Error(`Unknown wordlist: ${wordlist}`); 8 | } 9 | 10 | const rand = Math.floor(Math.random() * words.length); 11 | 12 | return words[rand] as string; 13 | }; 14 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Onboarding/utils/splitSeedPhrase.test.ts: -------------------------------------------------------------------------------- 1 | import splitSeedPhrase from './splitSeedPhrase'; 2 | 3 | describe('src/pages/Onboarding/utils/splitSeedPhrase', () => { 4 | it('trims whitespaces', () => { 5 | expect(splitSeedPhrase(' \n word word2 word3\n \n')).toStrictEqual([ 6 | 'word', 7 | 'word2', 8 | 'word3', 9 | ]); 10 | }); 11 | 12 | it('splits by tabulators', () => { 13 | expect(splitSeedPhrase('word word2 word3')).toStrictEqual([ 14 | 'word', 15 | 'word2', 16 | 'word3', 17 | ]); 18 | }); 19 | 20 | it('splits by newline', () => { 21 | expect(splitSeedPhrase('word\n word2 \nword3 ')).toStrictEqual([ 22 | 'word', 23 | 'word2', 24 | 'word3', 25 | ]); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Onboarding/utils/splitSeedPhrase.ts: -------------------------------------------------------------------------------- 1 | export default function splitSeedPhrase(seedPhrase: string): string[] { 2 | return seedPhrase.trim().split(/\s+/g); 3 | } 4 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Send/hooks/useSend/index.ts: -------------------------------------------------------------------------------- 1 | export * from './models'; 2 | export * from './useAVMSend'; 3 | export * from './useEVMSend'; 4 | export * from './usePVMSend'; 5 | export * from './useBTCSend'; 6 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Send/hooks/useValidAddressFromParams.ts: -------------------------------------------------------------------------------- 1 | import { useQueryParams } from '@core/ui'; 2 | 3 | export const useValidAddressFromParams = ( 4 | validateAddress: (address: string) => boolean, 5 | ) => { 6 | const params = useQueryParams(); 7 | const addressFromParams = params.get('address') ?? ''; 8 | 9 | return validateAddress(addressFromParams) ? addressFromParams : ''; 10 | }; 11 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Send/utils/correctAddressByPrefix.test.ts: -------------------------------------------------------------------------------- 1 | import { correctAddressByPrefix } from './correctAddressByPrefix'; 2 | 3 | describe('src/pages/Send/utils/correctAddressByPrefix', () => { 4 | it('should add the prefix when the address does not start with that', () => { 5 | const address = 'address'; 6 | expect(correctAddressByPrefix(address, 'PREFIX-')).toBe( 7 | `PREFIX-${address}`, 8 | ); 9 | }); 10 | it('sgould not duplicate the prefix when it is the start of the address', () => { 11 | const address = 'PREFIX-address'; 12 | expect(correctAddressByPrefix(address, 'PREFIX-')).toBe(address); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Send/utils/correctAddressByPrefix.ts: -------------------------------------------------------------------------------- 1 | export const correctAddressByPrefix = (address: string, prefix: string) => { 2 | return !address.startsWith(prefix) ? `${prefix}${address}` : address; 3 | }; 4 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/SignMessage/components/SignError.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | 3 | export function SignError() { 4 | const { t } = useTranslation(); 5 | return <>{t('Error, malformed request data')}; 6 | } 7 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/SignTransaction/models.ts: -------------------------------------------------------------------------------- 1 | export enum TransactionProgressState { 2 | NOT_APPROVED = 'TRANSACTION_NOT_APPROVED', 3 | PENDING = 'TRANSACTION_PENDING', 4 | SUCCESS = 'TRANSACTION_SUCCESS', 5 | ERROR = 'TRANSACTION_ERROR', 6 | } 7 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/SignTransaction/utils/getActiveStepForRemoteApproval.ts: -------------------------------------------------------------------------------- 1 | import { WalletConnectSessionInfo } from '@core/types'; 2 | 3 | export enum ApprovalStep { 4 | APPROVAL, 5 | CONNECT, 6 | SENT, 7 | LOADING, 8 | } 9 | 10 | export const getActiveStep = ( 11 | requestSent: boolean, 12 | activeSession: WalletConnectSessionInfo | null, 13 | isNewConnectionRequired: boolean, 14 | ) => { 15 | if (requestSent) { 16 | return ApprovalStep.SENT; 17 | } 18 | if (activeSession && !isNewConnectionRequired) { 19 | return ApprovalStep.APPROVAL; 20 | } 21 | if (isNewConnectionRequired) { 22 | return ApprovalStep.CONNECT; 23 | } 24 | return ApprovalStep.LOADING; 25 | }; 26 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Swap/components/SlippageToolTip.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | import { InfoCircleIcon, Tooltip } from '@avalabs/core-k2-components'; 3 | 4 | export function SlippageToolTip() { 5 | const { t } = useTranslation(); 6 | 7 | return ( 8 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Swap/components/SwapPendingToast.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Card, 3 | CircularProgress, 4 | Grow, 5 | IconButton, 6 | Stack, 7 | Typography, 8 | XIcon, 9 | } from '@avalabs/core-k2-components'; 10 | 11 | export const SwapPendingToast = ({ onDismiss, children }) => ( 12 | 13 | 14 | 18 | 19 | 20 | 21 | {children} 22 | 23 | 24 | 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /apps/legacy/src/pages/Swap/models.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NetworkTokenWithBalance, 3 | TokenWithBalanceERC20, 4 | TokenWithBalanceSPL, 5 | } from '@avalabs/vm-module-types'; 6 | 7 | export type SwappableToken = 8 | | NetworkTokenWithBalance 9 | | TokenWithBalanceERC20 10 | | TokenWithBalanceSPL; 11 | -------------------------------------------------------------------------------- /apps/legacy/src/types/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.jpg' { 2 | const value: any; 3 | export default value; 4 | } 5 | 6 | declare module '*.png' { 7 | const value: any; 8 | export default value; 9 | } 10 | 11 | declare module '*.svg' { 12 | const value: any; 13 | export default value; 14 | } 15 | -------------------------------------------------------------------------------- /apps/legacy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "~/*": ["../../packages/service-worker/src/*"], 6 | "@/*": ["./src/*"], 7 | "@shared/*": ["../../src/*"] 8 | } 9 | }, 10 | "exclude": ["**/node_modules/*"], 11 | "include": ["./src", "../../packages/types/*.d.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /apps/next/README.md: -------------------------------------------------------------------------------- 1 | # ui 2 | -------------------------------------------------------------------------------- /apps/next/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */ 2 | 3 | module.exports = { 4 | clearMocks: true, 5 | preset: 'ts-jest', 6 | resolver: '/../../src/tests/resolver.js', 7 | testEnvironment: 'jest-environment-jsdom', 8 | setupFilesAfterEnv: ['/../../src/tests/setupTests.ts'], 9 | moduleNameMapper: { 10 | '^@/(.*)': '/src/$1', 11 | '^@shared/(.*)': '/../../src/$1', 12 | '\\.(css|less|scss)$': 'identity-obj-proxy', 13 | '^uuid$': require.resolve('uuid'), 14 | '^lodash-es$': require.resolve('lodash'), 15 | }, 16 | transform: { 17 | '^.+\\.(js|jsx)$': 'babel-jest', 18 | }, 19 | transformIgnorePatterns: [`/node_modules/(?!micro-eth-signer)`], 20 | modulePathIgnorePatterns: ['/dist/'], 21 | }; 22 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/de/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/hi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/ja/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/ko/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/ru/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/tr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/manifest/_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "__NAME__", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appDesc": { 7 | "message": "Your home for Avalanche (AVAX) and beyond.", 8 | "description": "The description of the extension, displayed in the web store." 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/next/src/components/BrandName/BrandName.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from '@avalabs/k2-alpine'; 2 | 3 | interface BrandNameProps { 4 | height?: number; 5 | width?: number; 6 | margin?: string; 7 | padding?: string; 8 | } 9 | 10 | export function BrandName({ 11 | height, 12 | width, 13 | margin = '0', 14 | padding = '0', 15 | }: BrandNameProps) { 16 | return ( 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /apps/next/src/components/BrandName/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BrandName'; 2 | -------------------------------------------------------------------------------- /apps/next/src/images/Core_logo_black_text_white_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/Core_logo_black_text_white_background.png -------------------------------------------------------------------------------- /apps/next/src/images/Core_logo_white_text_black_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/Core_logo_white_text_black_background.png -------------------------------------------------------------------------------- /apps/next/src/images/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/android-chrome-512x512.png -------------------------------------------------------------------------------- /apps/next/src/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/next/src/images/beta-logos/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/beta-logos/apple-touch-icon.png -------------------------------------------------------------------------------- /apps/next/src/images/beta-logos/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/beta-logos/icon-16.png -------------------------------------------------------------------------------- /apps/next/src/images/beta-logos/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/beta-logos/icon-192.png -------------------------------------------------------------------------------- /apps/next/src/images/beta-logos/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/beta-logos/icon-256.png -------------------------------------------------------------------------------- /apps/next/src/images/beta-logos/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/beta-logos/icon-32.png -------------------------------------------------------------------------------- /apps/next/src/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/favicon.ico -------------------------------------------------------------------------------- /apps/next/src/images/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/icon-128.png -------------------------------------------------------------------------------- /apps/next/src/images/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/icon-16.png -------------------------------------------------------------------------------- /apps/next/src/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/icon-192.png -------------------------------------------------------------------------------- /apps/next/src/images/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/icon-32.png -------------------------------------------------------------------------------- /apps/next/src/images/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/apps/next/src/images/icon-48.png -------------------------------------------------------------------------------- /apps/next/src/images/no_image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /apps/next/src/localization/externalPhrases.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file should contain any translations that are present directly in our code. 3 | * E.g. if you want to add strings that are returned by APIs, they would not be caught 4 | * by i18next scanner. 5 | */ 6 | 7 | import { t } from 'i18next'; 8 | 9 | // ---- DeBank API ---- 10 | t('Deposit'); 11 | t('Farming'); 12 | t('Governance'); 13 | t('Insurance Buyer'); 14 | t('Investment'); 15 | t('Lending'); 16 | t('Liquidity Pool'); 17 | t('Locked'); 18 | t('Perpetuals'); 19 | t('Rewards'); 20 | t('Staked'); 21 | t('TokenSets'); 22 | t('Vesting'); 23 | t('Yield'); 24 | -------------------------------------------------------------------------------- /apps/next/src/pages/LockScreen/LockScreen.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from 'react'; 2 | 3 | export const LockScreen: FC = () => { 4 | return
LockScreen is under construction
; 5 | }; 6 | -------------------------------------------------------------------------------- /apps/next/src/pages/LockScreen/index.ts: -------------------------------------------------------------------------------- 1 | export * from './LockScreen'; 2 | -------------------------------------------------------------------------------- /apps/next/src/pages/Onboarding/Onboarding.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import { Onboarding } from './Onboarding'; 3 | 4 | jest.mock('react-i18next', () => ({ 5 | useTranslation: () => ({ 6 | t: (key: string) => key, 7 | }), 8 | })); 9 | 10 | describe('pages/Onboarding', () => { 11 | it('renders', async () => { 12 | const { container } = render(); 13 | 14 | expect(container.innerHTML).toContain('Welcome to new Core!'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /apps/next/src/pages/Onboarding/Onboarding.tsx: -------------------------------------------------------------------------------- 1 | import { Stack, Typography } from '@avalabs/k2-alpine'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | export function Onboarding() { 5 | const { t } = useTranslation(); 6 | 7 | return ( 8 | 16 | {t('😇')} 17 | {t('Welcome to new Core!')} 18 | {t('We are excited to see you!')} 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /apps/next/src/pages/Onboarding/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './Onboarding'; 2 | -------------------------------------------------------------------------------- /apps/next/src/popup/app.tsx: -------------------------------------------------------------------------------- 1 | import { CircularProgress, toast } from '@avalabs/k2-alpine'; 2 | import { 3 | AccountsContextProvider, 4 | NetworkContextProvider, 5 | OnboardingContextProvider, 6 | } from '@core/ui'; 7 | 8 | import { Onboarding } from '@/pages/Onboarding'; 9 | 10 | export function App() { 11 | return ( 12 | 13 | 14 | toast.error(message)} 16 | LoadingComponent={CircularProgress} 17 | OnboardingScreen={Onboarding} 18 | > 19 | <> 20 | 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /apps/next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "~/*": ["../../packages/service-worker/src/*"], 6 | "@/*": ["./src/*"], 7 | "@shared/*": ["../../src/*"] 8 | } 9 | }, 10 | "exclude": ["**/node_modules/*"], 11 | "include": ["./src", "../../packages/types/*.d.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/preset-env'], 3 | }; 4 | -------------------------------------------------------------------------------- /build-scripts/getEnvVars.ts: -------------------------------------------------------------------------------- 1 | import { loadEnv } from '@rsbuild/core'; 2 | import path from 'path'; 3 | 4 | export const getEnvVars = (mode: 'dev' | 'production') => { 5 | const { parsed } = loadEnv({ 6 | cwd: path.resolve(__dirname, '..'), 7 | mode, 8 | }); 9 | 10 | return Object.entries(parsed).reduce>( 11 | (accumulator, [envVariable, value]) => ({ 12 | ...accumulator, 13 | [`process.env.${envVariable}`]: JSON.stringify(value), 14 | }), 15 | {}, 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /build-scripts/readCoreCliArgument.mjs: -------------------------------------------------------------------------------- 1 | export const readCoreCliArgument = (lookup) => { 2 | return process.argv 3 | .slice(2) 4 | .find((arg) => arg.startsWith(`--core-${lookup}`)) 5 | ?.split('=')[1]; 6 | }; 7 | -------------------------------------------------------------------------------- /build-scripts/zipscript.mjs: -------------------------------------------------------------------------------- 1 | import zip from 'bestzip'; 2 | import pjson from '../package.json' with { type: 'json' }; 3 | import fs from 'fs'; 4 | import { readCoreCliArgument } from './readCoreCliArgument.mjs'; 5 | 6 | const { version } = pjson; 7 | 8 | if (!fs.existsSync('builds')) { 9 | fs.mkdirSync('builds'); 10 | } 11 | 12 | const gen = readCoreCliArgument('gen') || 'legacy'; 13 | const cwd = gen === 'legacy' ? 'dist' : 'dist-next'; 14 | 15 | zip({ 16 | cwd, 17 | source: '*', 18 | destination: `../builds/avalanche-wallet-extension${gen === 'next' ? '-next' : ''}.zip`, 19 | }) 20 | .then(() => { 21 | console.log(`version ${version} (${gen}) successfully created in /builds`); 22 | }) 23 | .catch((err) => { 24 | console.error(err.stack); 25 | process.exit(1); 26 | }); 27 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | const types = [ 2 | 'build', 3 | 'ci', 4 | 'docs', 5 | 'feat', 6 | 'fix', 7 | 'perf', 8 | 'refactor', 9 | 'revert', 10 | 'style', 11 | 'test', 12 | 'chore', 13 | ]; 14 | 15 | module.exports = { 16 | extends: ['@commitlint/config-angular'], 17 | rules: { 'type-enum': [2, 'always', types] }, 18 | }; 19 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |

Documentation

2 | 3 |
4 | 5 | ## Table of contents 6 | 7 | 1. [Architecture](01-Architecture.md) 8 | 2. [Backgound script](02-Background-script.md) 9 | 3. [Storage](03-Storage.md) 10 | 4. [Frontend](04-Frontend.md) 11 | 5. [Dapp connections](05-Dapp-connections.md) 12 | 6. [Ledger](06-Ledger.md) 13 | 7. [Localization](07-Localization.md) 14 | 8. [Analytics and feature flags](08-Analytics-and-Feature-Flags.md) 15 | 9. [Keystone](09-Keystone.md) 16 | -------------------------------------------------------------------------------- /docs/diagrams/README.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | This is a break down of the architecture of this extension. These files can be opened in [draw.io](https://app.diagrams.net/) or you can use vs code with the draw io extension. The extension will allow you to do everything the website will and is way more convenient. 4 | -------------------------------------------------------------------------------- /docs/diagrams/inpage-provider-architecture.drawio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/diagrams/inpage-provider-architecture.drawio -------------------------------------------------------------------------------- /docs/images/address-derivation.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/address-derivation.drawio.png -------------------------------------------------------------------------------- /docs/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/architecture.png -------------------------------------------------------------------------------- /docs/images/background-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/background-architecture.png -------------------------------------------------------------------------------- /docs/images/fireblocks-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/fireblocks-import.png -------------------------------------------------------------------------------- /docs/images/fireblocks-signing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/fireblocks-signing.png -------------------------------------------------------------------------------- /docs/images/inpage-initialization-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/inpage-initialization-process.png -------------------------------------------------------------------------------- /docs/images/inpage-provider-communication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/inpage-provider-communication.png -------------------------------------------------------------------------------- /docs/images/ledger-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/ledger-architecture.png -------------------------------------------------------------------------------- /docs/images/ledger-signing-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/ledger-signing-flow.png -------------------------------------------------------------------------------- /docs/images/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/screenshot1.png -------------------------------------------------------------------------------- /docs/images/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/screenshot2.png -------------------------------------------------------------------------------- /docs/images/seedless-onboarding-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/seedless-onboarding-flow.png -------------------------------------------------------------------------------- /docs/images/seedless-signing-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/seedless-signing-flow.png -------------------------------------------------------------------------------- /docs/images/wallet-connect-pairing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/wallet-connect-pairing.png -------------------------------------------------------------------------------- /docs/images/wallet-connect-signing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/docs/images/wallet-connect-signing.png -------------------------------------------------------------------------------- /packages/common/README.md: -------------------------------------------------------------------------------- 1 | # common 2 | -------------------------------------------------------------------------------- /packages/common/jest.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */ 2 | 3 | module.exports = { 4 | clearMocks: true, 5 | preset: 'ts-jest', 6 | resolver: '/../../src/tests/resolver.js', 7 | testEnvironment: 'jest-environment-jsdom', 8 | setupFilesAfterEnv: ['/../../src/tests/setupTests.ts'], 9 | moduleNameMapper: { 10 | '^uuid$': require.resolve('uuid'), 11 | '\\.(css|less|scss)$': 'identity-obj-proxy', 12 | '^@shared/(.*)': '/../../src/$1', 13 | }, 14 | transform: { 15 | '^.+\\.(js|jsx)$': 'babel-jest', 16 | }, 17 | modulePathIgnorePatterns: ['/dist/'], 18 | }; 19 | -------------------------------------------------------------------------------- /packages/common/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './script-names'; 2 | export * as Monitoring from './monitoring'; 3 | export * from './constants'; 4 | export * from './feature-flags'; 5 | export * from './utils'; 6 | export * from './initI18n'; 7 | -------------------------------------------------------------------------------- /packages/common/src/monitoring/index.ts: -------------------------------------------------------------------------------- 1 | import sentryCaptureException, { 2 | SentryExceptionTypes, 3 | } from './sentryCaptureException'; 4 | import sharedSentryConfig from './sharedSentryConfig'; 5 | 6 | export { sentryCaptureException, sharedSentryConfig, SentryExceptionTypes }; 7 | -------------------------------------------------------------------------------- /packages/common/src/script-names.ts: -------------------------------------------------------------------------------- 1 | export const CONTENT_SCRIPT = 'avalanche-contentscript'; 2 | export const EXTENSION_SCRIPT = 'avalanche-extension'; 3 | export const INPAGE_SCRIPT = 'avalanche-inpage'; 4 | export const OFFSCREEN_SCRIPT = 'avalanche-offscreen'; 5 | -------------------------------------------------------------------------------- /packages/common/src/utils/account.ts: -------------------------------------------------------------------------------- 1 | import { Account } from '@core/types'; 2 | 3 | export function getAllAddressesForAccount(acc: Partial) { 4 | return [ 5 | acc.addressC, 6 | acc.addressBTC, 7 | acc.addressAVM, 8 | acc.addressPVM, 9 | acc.addressCoreEth, 10 | acc.addressHVM, 11 | acc.addressSVM, 12 | ].filter((addr): addr is string => typeof addr === 'string'); 13 | } 14 | 15 | export function getAllAddressesForAccounts(accounts: Account[]): string[] { 16 | return accounts 17 | .flatMap(getAllAddressesForAccount) 18 | .filter((v) => typeof v === 'string'); 19 | } 20 | -------------------------------------------------------------------------------- /packages/common/src/utils/accounts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './accountTypeGuards'; 2 | -------------------------------------------------------------------------------- /packages/common/src/utils/actions/getUpdatedActionData.ts: -------------------------------------------------------------------------------- 1 | import { SigningData } from '@avalabs/vm-module-types'; 2 | 3 | export const getUpdatedSigningData = ( 4 | oldSigningData?: SigningData, 5 | newSigningData?: SigningData, 6 | ): SigningData | undefined => { 7 | if (!oldSigningData) { 8 | return newSigningData; 9 | } else if (!newSigningData) { 10 | return oldSigningData; 11 | } 12 | 13 | return { 14 | ...oldSigningData, 15 | ...newSigningData, 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/common/src/utils/array.ts: -------------------------------------------------------------------------------- 1 | export const areArraysOverlapping = ( 2 | listA: unknown[], 3 | listB: unknown[], 4 | ): boolean => { 5 | return listA.some((itemFromA) => listB.includes(itemFromA)); 6 | }; 7 | -------------------------------------------------------------------------------- /packages/common/src/utils/balance/getPriceChangeValues.ts: -------------------------------------------------------------------------------- 1 | import { TokensPriceShortData } from '@core/types'; 2 | 3 | export function getPriceChangeValues( 4 | tokenSymbol: string, 5 | balanceInCurrency?: number, 6 | priceChanges?: TokensPriceShortData, 7 | ) { 8 | if (!priceChanges) { 9 | return { 10 | percentage: undefined, 11 | value: 0, 12 | }; 13 | } 14 | const symbol = tokenSymbol.toLowerCase(); 15 | const tokenChangePercentage = priceChanges[symbol]?.priceChangePercentage; 16 | const tokenChangeValue = 17 | (balanceInCurrency || 0) * 18 | ((priceChanges[symbol]?.priceChangePercentage || 0) / 100); 19 | 20 | return { 21 | percentage: tokenChangePercentage, 22 | value: tokenChangeValue, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /packages/common/src/utils/balance/getTokenValue.test.ts: -------------------------------------------------------------------------------- 1 | import { getTokenValue } from './getTokenValue'; 2 | 3 | describe('src/background/services/balances/utils/getTokenValue.ts', () => { 4 | it('should return 0 if amount is undefined', () => { 5 | const result = getTokenValue(5, undefined); 6 | expect(result).toEqual(0); 7 | }); 8 | it('should return expected value when amount is available', () => { 9 | const result = getTokenValue(5, 100000); 10 | expect(result).toEqual(1); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/common/src/utils/balance/getTokenValue.ts: -------------------------------------------------------------------------------- 1 | export function getTokenValue(decimals: number, amount?: number) { 2 | return amount === undefined ? 0 : amount / 10 ** decimals; 3 | } 4 | -------------------------------------------------------------------------------- /packages/common/src/utils/balance/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getPriceChangeValues'; 2 | export * from './getTokenValue'; 3 | export * from './groupTokensByType'; 4 | export * from './isTokenWithBalanceAVM'; 5 | export * from './isTokenWithBalancePVM'; 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/balance/isTokenWithBalanceAVM.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TokenWithBalance, 3 | TokenWithBalanceAVM, 4 | } from '@avalabs/vm-module-types'; 5 | 6 | export const isTokenWithBalanceAVM = ( 7 | balance?: TokenWithBalance, 8 | ): balance is TokenWithBalanceAVM => { 9 | if (!balance) { 10 | return false; 11 | } 12 | 13 | return 'balancePerType' in balance && 'locked' in balance.balancePerType; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/common/src/utils/balance/isTokenWithBalancePVM.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TokenWithBalance, 3 | TokenWithBalancePVM, 4 | } from '@avalabs/vm-module-types'; 5 | 6 | export const isTokenWithBalancePVM = ( 7 | balance?: TokenWithBalance, 8 | ): balance is TokenWithBalancePVM => { 9 | if (!balance) { 10 | return false; 11 | } 12 | return ( 13 | 'balancePerType' in balance && 'lockedStaked' in balance.balancePerType 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/common/src/utils/bigintToBig.test.ts: -------------------------------------------------------------------------------- 1 | import Big from 'big.js'; 2 | import { bigintToBig } from './bigintToBig'; 3 | 4 | describe('utils/bigintToBig', () => { 5 | it('should return the Big value', () => { 6 | expect(bigintToBig(2000000000000n, 9)).toEqual(new Big(2000)); 7 | expect(bigintToBig(2000000000000n, 0)).toEqual(new Big(2000000000000)); 8 | expect(bigintToBig(2000000000000n, -1)).toEqual(new Big(20000000000000)); 9 | expect(bigintToBig(2000000000000n, 16)).toEqual(new Big(0.0002)); 10 | expect(bigintToBig(0n, 9)).toEqual(new Big(0)); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/common/src/utils/bigintToBig.ts: -------------------------------------------------------------------------------- 1 | import { bnToBig } from '@avalabs/core-utils-sdk'; 2 | import Big from 'big.js'; 3 | import { BN } from 'bn.js'; 4 | 5 | export function bigintToBig(amount: bigint, denomination: number): Big { 6 | return bnToBig(new BN(amount.toString()), denomination); 7 | } 8 | -------------------------------------------------------------------------------- /packages/common/src/utils/bridge/getBridgedAssetSymbol.ts: -------------------------------------------------------------------------------- 1 | import { BridgeTransfer } from '@avalabs/bridge-unified'; 2 | import { BridgeTransaction } from '@avalabs/core-bridge-sdk'; 3 | import { isUnifiedBridgeTransfer } from './isUnifiedBridgeTransfer'; 4 | 5 | export const getBridgedAssetSymbol = ( 6 | tx: BridgeTransfer | BridgeTransaction, 7 | ): string => { 8 | if (isUnifiedBridgeTransfer(tx)) { 9 | return tx.asset.symbol; 10 | } 11 | 12 | return tx.symbol; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/common/src/utils/bridge/getNativeTokenSymbol.ts: -------------------------------------------------------------------------------- 1 | import { Blockchain, getNativeSymbol } from '@avalabs/core-bridge-sdk'; 2 | import { Chain } from '@avalabs/bridge-unified'; 3 | 4 | export const getNativeTokenSymbol = (chain: Blockchain | Chain) => { 5 | if (typeof chain === 'object') { 6 | return chain.networkToken.symbol; 7 | } 8 | 9 | return getNativeSymbol(chain); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/common/src/utils/bridge/index.ts: -------------------------------------------------------------------------------- 1 | export * from './blockchainConversion'; 2 | export * from './findMatchingBridgeAsset'; 3 | export * from './getBridgedAssetSymbol'; 4 | export * from './isAddressBlockedError'; 5 | export * from './isUnifiedBridgeTransfer'; 6 | export * from './getNativeTokenSymbol'; 7 | export * from './bridgeEventFilters'; 8 | export * from './filterBridgeStateToNetwork'; 9 | -------------------------------------------------------------------------------- /packages/common/src/utils/bridge/isAddressBlockedError.ts: -------------------------------------------------------------------------------- 1 | import { ErrorReason } from '@avalabs/bridge-unified'; 2 | 3 | export const isAddressBlockedError = (err?: unknown) => { 4 | return ( 5 | !!err && 6 | err instanceof Error && 7 | err.message === ErrorReason.ADDRESS_IS_BLOCKED 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/common/src/utils/bridge/isUnifiedBridgeTransfer.ts: -------------------------------------------------------------------------------- 1 | import { BridgeTransaction } from '@avalabs/core-bridge-sdk'; 2 | import { BridgeTransfer } from '@avalabs/bridge-unified'; 3 | 4 | export const isUnifiedBridgeTransfer = ( 5 | transfer?: BridgeTransaction | BridgeTransfer, 6 | ): transfer is BridgeTransfer => { 7 | return transfer !== undefined && 'type' in transfer; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/common/src/utils/bridgeTransactionUtils.ts: -------------------------------------------------------------------------------- 1 | import { BridgeTransaction } from '@avalabs/core-bridge-sdk'; 2 | import { BridgeTransfer } from '@avalabs/bridge-unified'; 3 | import { TxHistoryItem } from '@core/types'; 4 | 5 | export const ETHEREUM_ADDRESS = '0x0000000000000000000000000000000000000000'; 6 | 7 | export function isPendingBridgeTransaction( 8 | item: TxHistoryItem | BridgeTransaction | BridgeTransfer, 9 | ): item is BridgeTransaction | BridgeTransfer { 10 | return 'addressBTC' in item || 'sourceChain' in item; 11 | } 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/canSkipApproval.ts: -------------------------------------------------------------------------------- 1 | import { runtime } from 'webextension-polyfill'; 2 | 3 | import { isSyncDomain } from './getSyncDomain'; 4 | import { isActiveTab } from './isActiveTab'; 5 | 6 | type SkipApprovalOptions = { 7 | allowInactiveTabs?: boolean; 8 | domainWhitelist?: string[]; 9 | }; 10 | 11 | export const canSkipApproval = async ( 12 | domain: string, 13 | tabId: number, 14 | { allowInactiveTabs, domainWhitelist }: SkipApprovalOptions = {}, 15 | ) => { 16 | if (!isSyncDomain(domain, domainWhitelist)) { 17 | return false; 18 | } 19 | 20 | return ( 21 | allowInactiveTabs || 22 | domain === runtime.id || // chrome.tabs.get(...) does not see extension popup 23 | (await isActiveTab(tabId)) 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /packages/common/src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const USDC_ADDRESS_C_CHAIN = 2 | '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e' as const; 3 | 4 | export const USDC_ADDRESS_ETHEREUM = 5 | '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' as const; 6 | 7 | export const USDC_ADDRESS_SOLANA = 8 | 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' as const; 9 | 10 | export const USDC_ADDRESSES = [ 11 | USDC_ADDRESS_C_CHAIN, 12 | USDC_ADDRESS_ETHEREUM, 13 | USDC_ADDRESS_SOLANA, 14 | ] as const; 15 | -------------------------------------------------------------------------------- /packages/common/src/utils/createMnemonicPhrase.ts: -------------------------------------------------------------------------------- 1 | import { Mnemonic } from 'ethers'; 2 | 3 | export function createNewMnemonic(): string { 4 | const randomBytes = crypto.getRandomValues(new Uint8Array(32)); 5 | return Mnemonic.entropyToPhrase(randomBytes); 6 | } 7 | -------------------------------------------------------------------------------- /packages/common/src/utils/distributiveomit.ts: -------------------------------------------------------------------------------- 1 | // if you want to remove properties from a union ype, you can use this 2 | // currently working stackoverflow answer: https://stackoverflow.com/questions/57103834/typescript-omit-a-property-from-all-interfaces-in-a-union-but-keep-the-union-s/57103940#57103940 3 | 4 | export type DistributiveOmit = T extends any 5 | ? Omit 6 | : never; 7 | -------------------------------------------------------------------------------- /packages/common/src/utils/environment.ts: -------------------------------------------------------------------------------- 1 | export function isDevelopment() { 2 | return process.env.NODE_ENV === 'development'; 3 | } 4 | 5 | export function isProductionBuild() { 6 | return process.env.RELEASE === 'production'; 7 | } 8 | -------------------------------------------------------------------------------- /packages/common/src/utils/errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './errorHelpers'; 2 | -------------------------------------------------------------------------------- /packages/common/src/utils/exponentialBackoff.ts: -------------------------------------------------------------------------------- 1 | type ExponentialBackoffOptions = { 2 | attempt: number; // The current attempt number 3 | startsAfter?: number; // The attempt number after which the delay should start increasing. 4 | maxDelay?: number; // The maximum delay (in ms), to avoid waiting for ridiculously long time before next attempts. 5 | }; 6 | 7 | /** 8 | * Returns the delay (in milliseconds) before another attempt should start. 9 | * Runs on power of 2. 10 | */ 11 | export const getExponentialBackoffDelay = ({ 12 | attempt, 13 | startsAfter = 3, 14 | maxDelay = 30000, 15 | }: ExponentialBackoffOptions) => { 16 | return Math.min(maxDelay, 2 ** Math.max(1, attempt - startsAfter + 1) * 1000); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/common/src/utils/fetchAndVerify.ts: -------------------------------------------------------------------------------- 1 | import z from 'zod'; 2 | import type { ZodSchema } from 'zod'; 3 | 4 | export async function fetchAndVerify( 5 | fetchOptions: Parameters, 6 | schema: T, 7 | ): Promise> { 8 | const response = await fetch(...fetchOptions); 9 | 10 | if (!response.ok) { 11 | throw new Error(`Request failed with status ${response.status}`); 12 | } 13 | 14 | const responseJson = await response.json(); 15 | return schema.parse(responseJson); 16 | } 17 | -------------------------------------------------------------------------------- /packages/common/src/utils/filterFalsyValues.ts: -------------------------------------------------------------------------------- 1 | import { filter, Observable } from 'rxjs'; 2 | 3 | export function filterFalseyValues() { 4 | return (observer: Observable) => observer.pipe(filter((value) => !!value)); 5 | } 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/findTokenForAsset.ts: -------------------------------------------------------------------------------- 1 | import { Blockchain } from '@avalabs/core-bridge-sdk'; 2 | import { TokenWithBalance } from '@avalabs/vm-module-types'; 3 | 4 | export function findTokenForAsset( 5 | symbol: string, 6 | nativeChain: Blockchain, 7 | tokens: TokenWithBalance[], 8 | ) { 9 | // When the source is Avalanche use the wrapped version of the symbol e.g. BTC.b 10 | const wrappedSymbol = getWrappedSymbol(symbol, nativeChain); 11 | 12 | return tokens.find((t) => t.symbol === symbol || t.symbol === wrappedSymbol); 13 | } 14 | 15 | function getWrappedSymbol(symbol: string, chain: Blockchain): string { 16 | if (chain === Blockchain.ETHEREUM) { 17 | return `${symbol}.e`; 18 | } else if (chain === Blockchain.BITCOIN) { 19 | return `${symbol}.b`; 20 | } 21 | return symbol; 22 | } 23 | -------------------------------------------------------------------------------- /packages/common/src/utils/fireblocks/getFireblocksBtcAccessErrorCode.ts: -------------------------------------------------------------------------------- 1 | import { BTC_ACCESS_ERROR_PREFIX } from '@core/types'; 2 | 3 | export function getFireblocksBtcAccessErrorCode(message: string) { 4 | const [, code] = message.split(BTC_ACCESS_ERROR_PREFIX); 5 | 6 | if (typeof code === 'undefined' || code === '') { 7 | return null; 8 | } 9 | 10 | return parseInt(code); 11 | } 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/fireblocks/isFireblocksApiSupported.ts: -------------------------------------------------------------------------------- 1 | import { FireblocksAccount } from '@core/types'; 2 | 3 | // If we have the BTC address for a Fireblocks account, that means that we were 4 | // provided the correct API credentials (otherwise we wouldn't be able to fetch 5 | // the address). 6 | export function isFireblocksApiSupported(account?: FireblocksAccount) { 7 | return Boolean(account?.addressBTC); 8 | } 9 | -------------------------------------------------------------------------------- /packages/common/src/utils/getAccountKey.test.ts: -------------------------------------------------------------------------------- 1 | import { getAccountKey } from './getAccountKey'; 2 | 3 | describe('utils/getAccountKey()', () => { 4 | const address = 'asdrty123'; 5 | it('should return the address as an account key', () => { 6 | expect(getAccountKey({ address })).toBe(address); 7 | }); 8 | 9 | it('should return a test suffix', () => { 10 | expect(getAccountKey({ address, isTestnet: true })).toBe(`${address}-test`); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/common/src/utils/getAccountKey.ts: -------------------------------------------------------------------------------- 1 | interface GetAccountKey { 2 | address: string; 3 | isTestnet?: boolean; 4 | } 5 | 6 | export function getAccountKey({ address, isTestnet }: GetAccountKey) { 7 | const accountSuffix = !isTestnet ? '' : '-test'; 8 | return `${address}${accountSuffix}`; 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/utils/getAddressForChain.ts: -------------------------------------------------------------------------------- 1 | import { NetworkVMType } from '@avalabs/vm-module-types'; 2 | 3 | import { Account, NetworkWithCaipId } from '@core/types'; 4 | 5 | import { mapAddressesToVMs } from './address'; 6 | 7 | export function getAddressForChain( 8 | network?: NetworkWithCaipId, 9 | account?: Partial, 10 | ) { 11 | if (!network || !account) { 12 | return ''; 13 | } 14 | 15 | return ( 16 | mapAddressesToVMs(account)[network.vmName satisfies NetworkVMType] ?? '' 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /packages/common/src/utils/getCoreWebUrl.ts: -------------------------------------------------------------------------------- 1 | export const getCoreWebUrl = (address?: string, networkId?: number) => { 2 | const baseCoreWebUrl = process.env.CORE_WEB_BASE_URL; 3 | if (!address) { 4 | return baseCoreWebUrl; 5 | } 6 | 7 | if (address && networkId) { 8 | return `${baseCoreWebUrl}/account/${address}?network=${networkId}`; 9 | } 10 | return `${baseCoreWebUrl}/account/${address}`; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/getDefaultChainIds.ts: -------------------------------------------------------------------------------- 1 | import { ChainId } from '@avalabs/core-chains-sdk'; 2 | 3 | export function getXPChainIds(isMainnet: boolean) { 4 | const xChainId = isMainnet ? ChainId.AVALANCHE_X : ChainId.AVALANCHE_TEST_X; 5 | const pChainId = isMainnet ? ChainId.AVALANCHE_P : ChainId.AVALANCHE_TEST_P; 6 | 7 | return [pChainId, xChainId]; 8 | } 9 | 10 | export function getDefaultChainIds(isMainnet: boolean) { 11 | return [ 12 | isMainnet ? ChainId.AVALANCHE_MAINNET_ID : ChainId.AVALANCHE_TESTNET_ID, 13 | ...getXPChainIds(isMainnet), 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /packages/common/src/utils/getHexStringToBytes.ts: -------------------------------------------------------------------------------- 1 | export function getHexStringToBytes(hex: string): number | null { 2 | if (!hex) return null; 3 | 4 | // the first 2 chars can be ignore since it indicates the hexadecimal representation ( -2 ) 5 | // the reason byte size is calculated this way => F in hex is the biggest number which can be represented with 4 bits (1111) 6 | // therefore 2 chars at a time can be represented in 1 byte which is 8 bits 7 | // so the byte value of a hex is the half of the character count 8 | 9 | return (hex.length - 2) / 2; 10 | } 11 | -------------------------------------------------------------------------------- /packages/common/src/utils/getSyncDomain.ts: -------------------------------------------------------------------------------- 1 | import { runtime } from 'webextension-polyfill'; 2 | import { SYNCED_DOMAINS } from '../constants'; 3 | 4 | export const isSyncDomain = ( 5 | domain: string, 6 | exposedDomainList: string[] = [], 7 | ) => { 8 | return [runtime.id, ...SYNCED_DOMAINS, ...exposedDomainList].some( 9 | (syncDomain) => { 10 | // Match exact domains, but also allow subdomains (i.e. develop.core-web.pages.dev) 11 | return syncDomain === domain || domain.endsWith(`.${syncDomain}`); 12 | }, 13 | ); 14 | }; 15 | 16 | /** 17 | * Returns the extension's ID for synced domains (i.e. the Core Suite apps) 18 | */ 19 | export const getSyncDomain = (domain: string) => { 20 | return isSyncDomain(domain) ? runtime.id : domain; 21 | }; 22 | -------------------------------------------------------------------------------- /packages/common/src/utils/hasAccountBalances.ts: -------------------------------------------------------------------------------- 1 | import { Account, Balances } from '@core/types'; 2 | import { getAllAddressesForAccount } from './account'; 3 | 4 | export function hasAccountBalances( 5 | balances: Balances, 6 | account: Partial, 7 | networkIds: number[], 8 | ) { 9 | const accountAddresses = getAllAddressesForAccount(account); 10 | 11 | return Object.entries(balances) 12 | .filter(([networkId]) => networkIds.includes(Number(networkId))) 13 | .some(([, item]) => { 14 | if (!item) { 15 | return false; 16 | } 17 | const balanceAddresses = Object.keys(item); 18 | 19 | return balanceAddresses.some((address) => { 20 | return accountAddresses.includes(address); 21 | }); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /packages/common/src/utils/hasUnconfirmedBalance.ts: -------------------------------------------------------------------------------- 1 | import BN from 'bn.js'; 2 | 3 | import { 4 | TokenWithBalance, 5 | TokenWithBalanceBTC, 6 | } from '@avalabs/vm-module-types'; 7 | 8 | export const hasUnconfirmedBalance = ( 9 | token: TokenWithBalance, 10 | ): token is TokenWithBalanceBTC & { unconfirmedBalance: BN } => { 11 | return 'unconfirmedBalance' in token && Boolean(token.unconfirmedBalance); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/common/src/utils/history/getAvaxAssetId.ts: -------------------------------------------------------------------------------- 1 | import { Avalanche } from '@avalabs/core-wallets-sdk'; 2 | 3 | export const getAvaxAssetId = (isTestnet: boolean) => 4 | isTestnet 5 | ? Avalanche.FujiContext.avaxAssetID 6 | : Avalanche.MainnetContext.avaxAssetID; 7 | -------------------------------------------------------------------------------- /packages/common/src/utils/history/index.ts: -------------------------------------------------------------------------------- 1 | export * from './isTxHistoryItem'; 2 | export * from './getAvaxAssetId'; 3 | -------------------------------------------------------------------------------- /packages/common/src/utils/history/isTxHistoryItem.ts: -------------------------------------------------------------------------------- 1 | import { NetworkVMType } from '@avalabs/vm-module-types'; 2 | import { TxHistoryItem } from '@core/types'; 3 | 4 | export function isNonXPHistoryItem( 5 | tx: TxHistoryItem, 6 | ): tx is TxHistoryItem< 7 | Exclude 8 | > { 9 | return tx.vmType !== 'AVM' && tx.vmType !== 'PVM'; 10 | } 11 | 12 | export function isPchainTxHistoryItem( 13 | tx: TxHistoryItem, 14 | ): tx is TxHistoryItem { 15 | return tx.vmType === 'PVM'; 16 | } 17 | -------------------------------------------------------------------------------- /packages/common/src/utils/ipsfResolverWithFallback.ts: -------------------------------------------------------------------------------- 1 | import { ipfsResolver } from '@avalabs/core-utils-sdk'; 2 | 3 | export const IPFS_URL = 'https://ipfs.io'; 4 | 5 | export function ipfsResolverWithFallback( 6 | sourceUrl: string | undefined, 7 | desiredGatewayPrefix: string = IPFS_URL, 8 | ) { 9 | if (!sourceUrl) { 10 | return ''; 11 | } 12 | 13 | try { 14 | return ipfsResolver(sourceUrl, desiredGatewayPrefix); 15 | } catch { 16 | return sourceUrl; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/common/src/utils/isActiveTab.ts: -------------------------------------------------------------------------------- 1 | import { tabs } from 'webextension-polyfill'; 2 | 3 | export const isActiveTab = async (tabId: number) => { 4 | try { 5 | const tab = await tabs.get(tabId); 6 | return Boolean(tab) && tab.active; 7 | } catch { 8 | return false; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /packages/common/src/utils/isAddressValid.test.ts: -------------------------------------------------------------------------------- 1 | import { isValidPvmAddress } from './isAddressValid'; 2 | import { utils } from '@avalabs/avalanchejs'; 3 | 4 | describe('src/utils/isAddressValid.ts', () => { 5 | const address = utils.formatBech32('test', new Uint8Array(2)); 6 | beforeEach(() => { 7 | jest.resetAllMocks(); 8 | }); 9 | 10 | afterEach(() => { 11 | jest.useRealTimers(); 12 | }); 13 | 14 | describe('isValidPvmAddress', () => { 15 | it('should return false if not valid', async () => { 16 | const result = isValidPvmAddress(`P-testAddress}`); 17 | expect(result).toEqual(false); 18 | }); 19 | it('should return true if valid', async () => { 20 | const result = isValidPvmAddress(`P-${address}`); 21 | expect(result).toEqual(true); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/common/src/utils/isBitcoin.ts: -------------------------------------------------------------------------------- 1 | import { Network, NetworkVMType } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isBitcoin(network?: Network) { 4 | return network?.vmName === NetworkVMType.BITCOIN; 5 | } 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/isBtcAddressInNetwork.ts: -------------------------------------------------------------------------------- 1 | import { 2 | isBase58AddressInNetwork, 3 | isBech32AddressInNetwork, 4 | } from '@avalabs/core-bridge-sdk'; 5 | 6 | /** 7 | * Check if the given address is a valid Bitcoin address 8 | * @param address Bitcoin address, bech32 or b58 9 | * @param isMainnet Verify address against mainnet or testnet 10 | */ 11 | export function isBtcAddressInNetwork(address: string, isMainnet: boolean) { 12 | return ( 13 | isBech32AddressInNetwork(address, isMainnet) || 14 | isBase58AddressInNetwork(address, isMainnet) 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/common/src/utils/isFailedToFetchError.test.ts: -------------------------------------------------------------------------------- 1 | import { isFailedToFetchError } from './isFailedToFetchError'; 2 | 3 | describe('src/utils/isFailedToFetchError', () => { 4 | it('recognizes network failures', () => { 5 | expect(isFailedToFetchError(new TypeError('Failed to fetch'))).toBe(true); 6 | expect(isFailedToFetchError(new Error('404 Not Found'))).toBe(false); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/common/src/utils/isFailedToFetchError.ts: -------------------------------------------------------------------------------- 1 | export const isFailedToFetchError = (err: unknown): boolean => { 2 | return err instanceof Error && /Failed to fetch/.test(err.message); 3 | }; 4 | -------------------------------------------------------------------------------- /packages/common/src/utils/isLedgerVersionCompatible.ts: -------------------------------------------------------------------------------- 1 | // ledgerAppVersion >= requiredAppVersion 2 | export function isLedgerVersionCompatible( 3 | ledgerAppVersion: string, 4 | requiredAppVersion: string, 5 | ) { 6 | const compare = ledgerAppVersion.localeCompare( 7 | requiredAppVersion, 8 | undefined, 9 | { 10 | numeric: true, 11 | sensitivity: 'base', 12 | }, 13 | ); 14 | 15 | // ledgerAppVersion > requiredAppVersion 16 | if (compare === 1) return true; 17 | // ledgerAppVersion = requiredAppVersion 18 | if (compare === 0) return true; 19 | // ledgerAppVersion < requiredAppVersion 20 | if (compare === -1) return false; 21 | } 22 | -------------------------------------------------------------------------------- /packages/common/src/utils/isLockStateChangedEvent.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionConnectionEvent, LockEvents } from '@core/types'; 2 | 3 | export function isLockStateChangedEvent( 4 | evt: ExtensionConnectionEvent, 5 | ): evt is ExtensionConnectionEvent { 6 | return evt.name === LockEvents.LOCK_STATE_CHANGED; 7 | } 8 | -------------------------------------------------------------------------------- /packages/common/src/utils/isPrimarySubnet.ts: -------------------------------------------------------------------------------- 1 | import { Avalanche } from '@avalabs/core-wallets-sdk'; 2 | 3 | export function isPrimarySubnet(subnetId: string) { 4 | return subnetId === Avalanche.MainnetContext.pBlockchainID; 5 | } 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/isSupportedBrowser.ts: -------------------------------------------------------------------------------- 1 | import { Browser, detect } from 'detect-browser'; 2 | 3 | export const supportedBrowsers: Browser[] = ['chrome']; 4 | export const isSupportedBrowser = () => { 5 | const browser = detect(); 6 | const isSupported = supportedBrowsers.includes( 7 | (browser?.name ?? '') as Browser, 8 | ); 9 | 10 | return isSupported; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/isSwimmerNetwork.ts: -------------------------------------------------------------------------------- 1 | import { ChainId, Network } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isSwimmer(network: Network) { 4 | return isSwimmerByChainId(network.chainId); 5 | } 6 | 7 | export function isSwimmerByChainId(chainId: number) { 8 | return !!(chainId === ChainId.SWIMMER || chainId === ChainId.SWIMMER_TESTNET); 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/utils/isTokenMalicious.ts: -------------------------------------------------------------------------------- 1 | import { TokenType, TokenWithBalance } from '@avalabs/vm-module-types'; 2 | import { Erc20TokenBalance } from '@avalabs/glacier-sdk'; 3 | import { NetworkContractToken } from '@avalabs/core-chains-sdk'; 4 | 5 | export const isTokenMalicious = ( 6 | token: TokenWithBalance | NetworkContractToken, 7 | ) => { 8 | if (!('type' in token) || token.type !== TokenType.ERC20) { 9 | return false; 10 | } 11 | 12 | return token.reputation === Erc20TokenBalance.tokenReputation.MALICIOUS; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/common/src/utils/isValidXpAddress.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/packages/common/src/utils/isValidXpAddress.ts -------------------------------------------------------------------------------- /packages/common/src/utils/isWalletStateUpdateEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | WalletEvents, 4 | WalletDetails, 5 | } from '@core/types'; 6 | 7 | export function isWalletStateUpdateEvent( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === WalletEvents.WALLET_STATE_UPDATE; 11 | } 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/jsonRpcEngine.ts: -------------------------------------------------------------------------------- 1 | import { JsonRpcEngine } from 'json-rpc-engine'; 2 | import { createFetchMiddleware } from 'eth-json-rpc-middleware'; 3 | import { Network } from '@avalabs/core-chains-sdk'; 4 | import { addGlacierAPIKeyIfNeeded } from './network/addGlacierAPIKeyIfNeeded'; 5 | 6 | export async function engine(network: Network) { 7 | const fetchMiddleware = createFetchMiddleware({ 8 | get rpcUrl() { 9 | return addGlacierAPIKeyIfNeeded(network.rpcUrl); 10 | }, 11 | }); 12 | const rpcEngine = new JsonRpcEngine(); 13 | rpcEngine.push(fetchMiddleware); 14 | return rpcEngine; 15 | } 16 | -------------------------------------------------------------------------------- /packages/common/src/utils/keystore/index.ts: -------------------------------------------------------------------------------- 1 | export * from './keystore'; 2 | export * from './cryptoHelpers'; 3 | export * as KeystoreFixtures from './keystore-fixtures'; 4 | -------------------------------------------------------------------------------- /packages/common/src/utils/keystore/keystore-fixtures/keystore-v2.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "salt": "2SjQXSMR87tBvYqbkwTFL61gEdwR", 4 | "pass_hash": "2NJf6rqPshCU69hMkPEMBLBZLfBKshHy68cWgNY7kNmAM988Qt", 5 | "keys": [ 6 | { 7 | "key": "C8JG3QvhF9XUiXMyAmQoTfTkWg5UySMPKeCrkGH8u67HrqStNtBxZyDxLY6NrSS8k51Fg3V", 8 | "iv": "Fc8Xyxmhd2X55sgjy4aTxN", 9 | "address": "X-EAZkJNdFBjVQQ7zS81hWCnRHfMKf3vpYH" 10 | }, 11 | { 12 | "key": "p52F7MGpyicfG2c7RXuKKKpUE7X9qjLX7qx2ju3mei58jU4vCxRQpjcR6RvSKbozphMT1s8", 13 | "iv": "N6fYr5gT4TJfB6Tzs9oLMN", 14 | "address": "X-7r1aDs2jiJHr1reFfLFzzKrprZruXVzqM" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/common/src/utils/keystore/keystore-fixtures/keystore-v3.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3.0", 3 | "salt": "kwkVtmPkafnwWbp65nYs2z9cQeN", 4 | "pass_hash": "2gid7yJzvyg2Mz4HUJLh3jvgumpDJmRu2PBopqHYacVjwisp1g", 5 | "keys": [ 6 | { 7 | "key": "uDvvzSQQxkFGhYUvDcRFmWtKbqJEZ8swKgMx7Ba3eWUoTMaikvV2oD2jUFzaS35WdP8rtqF", 8 | "iv": "AN8nLnaK84rfoKXtxm6evy", 9 | "address": "X-EAZkJNdFBjVQQ7zS81hWCnRHfMKf3vpYH" 10 | }, 11 | { 12 | "key": "PiLrcsSBZ1fBE9v3axsHycfhta6NwMf56qqGKgxswr4VSNGL3kZUQG8YCCRG2q7QDN8y5mp", 13 | "iv": "L7MojgHmudo2WpbMCdfgCg", 14 | "address": "X-7r1aDs2jiJHr1reFfLFzzKrprZruXVzqM" 15 | } 16 | ], 17 | "warnings": [ 18 | "This address listed in this file is for internal wallet use only. DO NOT USE THIS ADDRESS" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/common/src/utils/keystore/keystore-fixtures/keystore-v4.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "4.0", 3 | "salt": "UWLRsfsyjY51E1s8CVa7cvvMHMz", 4 | "pass_hash": "M6mzyfS4i4bKBxXQZFuQ6BsRnMSVMe7GnBd1HTmVLi2jcscPA", 5 | "keys": [ 6 | { 7 | "key": "s2RScHaFr6nr3JQkb8wNBbAPAWiGNkZRRmbUYY2tnxhCpdTgnHLyTDHXN4mdfEV4fVwFcMP", 8 | "iv": "A6jQMX7e6doGS6wVvdLzA" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/keystore/keystore-fixtures/keystore-v5.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "5.0", 3 | "salt": "TEUQMGR1XdHs5wb4SVSA7LriUhR", 4 | "pass_hash": "avkdK9YFLn1zfZjvBsB9ipKRzfqr4rvqBryVosB6NUgFiv9kd", 5 | "keys": [ 6 | { 7 | "key": "5jVaPDgXd9nm3DF6XWSbvpGFKVd5yujnYekQCoK4evkoMBAWNz7Nc7YVKYUc6RQJiPy47rh1kfc2uydapEuVieN51eeHRATGqQP4Rj5wjN1xwKVgEsxvGeAytMevbYE9L2y4nCPyHvVcPQB66d7B5kdgYv3N7QVd3K284skjfGsZbZAT16vinjkZry8ypdwt2UV7c6WbVFX72BuEAajapn5TdkWCpPHJZgTkVs9utfndxYMW9m", 8 | "iv": "Ak8DSMKMy4f1RXHSSt15KK" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/keystore/keystore-fixtures/keystore-v6-private-key.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "6.0", 3 | "salt": "gpREk7UQELwqHHi5Up745hiH9sM", 4 | "activeIndex": 0, 5 | "keys": [ 6 | { 7 | "key": "5yMG6VWZS7qBP6JPYUaU6pYLyEMkWgZfEnQDZmZfTKdEkgpcpwt43kTURFooL7rEmUAe5XhbXhKaeeHPH2wuHvjyvkYqRSVggGef81ZjZNZRUZy", 8 | "iv": "LkVD8xhaS2Pw6SQ7nT5r5N", 9 | "type": "singleton" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/common/src/utils/keystore/keystore-fixtures/keystore-v6.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "6.0", 3 | "salt": "2NgqFaoYSe5foo8oEtcdB658c7Eb", 4 | "activeIndex": 0, 5 | "keys": [ 6 | { 7 | "key": "KJYzUxFzn2EFazvAkfEgkbdJ7L2qeUTG5jTHUa9MunaNZWzNREd1GvYbwbUDdUsEu9Z5vB4kKW6x3farGCjtDHJ6c4nRCEnJKTUmFsBZ6CZqQ4MfXCMBXPvzvvDuv3VhYeE1LkiQHQRhEfKQGVaY282xDRifx3xyeT8ar18LxF3UPDNjX1D1EDLX4bTvbT4cChc8EPj9ufwXrov1y7Fcw3krJ5H87GnkwCZezzTxUeas1eTztZ", 8 | "iv": "TQei93ehgGWgUKXkLha8Ef", 9 | "type": "mnemonic" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /packages/common/src/utils/lowerCaseKeys.ts: -------------------------------------------------------------------------------- 1 | export const lowerCaseKeys = (obj: Record): Record => { 2 | return Object.fromEntries( 3 | Object.entries(obj).map(([key, value]) => [key.toLowerCase(), value]), 4 | ); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/makeBNLike.ts: -------------------------------------------------------------------------------- 1 | import { BNLike } from 'ethereumjs-util'; 2 | import { BigNumberish } from 'ethers'; 3 | 4 | export function makeBNLike( 5 | n: BigNumberish | undefined | null, 6 | ): BNLike | undefined { 7 | if (n == null) return undefined; 8 | return '0x' + BigInt(n).toString(16); 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/utils/measureDuration.ts: -------------------------------------------------------------------------------- 1 | export const measureDuration = ( 2 | id?: string, 3 | ): { 4 | measurementId: string; 5 | start: () => void; 6 | end: () => number; 7 | } => { 8 | const measurementId = id ?? crypto.randomUUID(); 9 | 10 | const start = () => { 11 | performance.mark(`${measurementId}-start`); 12 | }; 13 | 14 | const end = (): number => { 15 | const measurement = performance.measure( 16 | `${measurementId}-measurement`, 17 | `${measurementId}-start`, 18 | ); 19 | 20 | performance.clearMarks(`${measurementId}-start`); 21 | performance.clearMeasures(`${measurementId}-measurement`); 22 | 23 | return measurement.duration; 24 | }; 25 | 26 | return { measurementId, start, end }; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/addGlacierAPIKeyIfNeeded.ts: -------------------------------------------------------------------------------- 1 | export function addGlacierAPIKeyIfNeeded(url: string): string { 2 | if (!process.env.GLACIER_URL || !process.env.PROXY_URL) { 3 | return url; 4 | } 5 | 6 | // RPC urls returned in the token list are always using the production URL 7 | const knownHosts = new Set([ 8 | 'glacier-api.avax.network', 9 | 'proxy-api.avax.network', 10 | new URL(process.env.GLACIER_URL).host, 11 | new URL(process.env.PROXY_URL).host, 12 | ]); 13 | 14 | const urlObject = new URL(url); 15 | 16 | if (process.env.GLACIER_API_KEY && knownHosts.has(urlObject.host)) { 17 | urlObject.searchParams.append('token', process.env.GLACIER_API_KEY); 18 | return urlObject.toString(); 19 | } 20 | 21 | return url; 22 | } 23 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/buildGlacierAuthHeaders.ts: -------------------------------------------------------------------------------- 1 | import { CustomRpcHeaders } from '@core/types'; 2 | 3 | export const buildGlacierAuthHeaders = (apiKey: string): CustomRpcHeaders => { 4 | if (!apiKey) { 5 | return {}; 6 | } 7 | 8 | return { 9 | 'X-Glacier-Api-Key': apiKey, 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/isAvalancheNetwork.ts: -------------------------------------------------------------------------------- 1 | import { Network, ChainId } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isAvalancheNetwork(network: Network) { 4 | return isAvalancheChainId(network.chainId); 5 | } 6 | 7 | export function isAvalancheChainId(chainId: number) { 8 | return ( 9 | ChainId.AVALANCHE_MAINNET_ID === chainId || 10 | ChainId.AVALANCHE_LOCAL_ID === chainId || 11 | ChainId.AVALANCHE_TESTNET_ID === chainId 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/isAvalanchePchainNetwork.ts: -------------------------------------------------------------------------------- 1 | import { ChainId, Network, NetworkVMType } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isPchainNetwork(network?: Network) { 4 | if (!network) { 5 | return false; 6 | } 7 | return network.vmName === NetworkVMType.PVM; 8 | } 9 | 10 | export function isPchainNetworkId(chainId: number) { 11 | return ( 12 | ChainId.AVALANCHE_P === chainId || ChainId.AVALANCHE_TEST_P === chainId 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/isAvalancheXchainNetwork.ts: -------------------------------------------------------------------------------- 1 | import { ChainId, Network, NetworkVMType } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isXchainNetwork(network?: Network) { 4 | if (!network) { 5 | return false; 6 | } 7 | return network.vmName === NetworkVMType.AVM; 8 | } 9 | 10 | //TODO: Fix this once we figure out how to separate between x and p chain ID 11 | export function isXchainNetworkId(chainId: number) { 12 | return ( 13 | ChainId.AVALANCHE_X === chainId || ChainId.AVALANCHE_TEST_X === chainId 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/isBitcoinNetwork.ts: -------------------------------------------------------------------------------- 1 | import { Network, ChainId } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isBitcoinNetwork(network: Network) { 4 | return isBitcoinChainId(network.chainId); 5 | } 6 | 7 | export function isBitcoinChainId(chainId: number) { 8 | return ChainId.BITCOIN === chainId || ChainId.BITCOIN_TESTNET === chainId; 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/isEthereumNetwork.ts: -------------------------------------------------------------------------------- 1 | import { Network, ChainId } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isEthereumNetwork(network: Network) { 4 | return isEthereumChainId(network.chainId); 5 | } 6 | 7 | export function isEthereumChainId(chainId: number) { 8 | return ( 9 | ChainId.ETHEREUM_HOMESTEAD === chainId || 10 | ChainId.ETHEREUM_TEST_GOERLY === chainId || 11 | ChainId.ETHEREUM_TEST_RINKEBY === chainId || 12 | ChainId.ETHEREUM_TEST_SEPOLIA === chainId 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/isSolanaNetwork.ts: -------------------------------------------------------------------------------- 1 | import { Network, ChainId } from '@avalabs/core-chains-sdk'; 2 | 3 | export function isSolanaNetwork(network?: Network) { 4 | return network ? isSolanaChainId(network.chainId) : false; 5 | } 6 | 7 | export function isSolanaChainId(chainId: number) { 8 | return ( 9 | ChainId.SOLANA_DEVNET_ID === chainId || 10 | ChainId.SOLANA_MAINNET_ID === chainId || 11 | ChainId.SOLANA_TESTNET_ID === chainId 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /packages/common/src/utils/network/isValidHttpHeader.ts: -------------------------------------------------------------------------------- 1 | export const isValidHttpHeader = (name: string, value: string) => { 2 | try { 3 | new Headers({ 4 | [name]: value, 5 | }); 6 | return true; 7 | } catch { 8 | return false; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /packages/common/src/utils/nfts/getSmallImageForNFT.ts: -------------------------------------------------------------------------------- 1 | import { ipfsResolverWithFallback } from '../ipsfResolverWithFallback'; 2 | 3 | const COVALENT_IMG_SIZER = 4 | 'https://image-proxy.svc.prod.covalenthq.com/cdn-cgi/image'; 5 | 6 | /** 7 | * Covalent has an on the fly image resizer, it resolves image urls then resizes the image. 8 | * 9 | * This allows us to request smaller images depending on the UI needs 10 | * 11 | * @param imgUrl the url of the image to convert to size 12 | * @returns The url to the image which is sized at the time of request 13 | */ 14 | export function getSmallImageForNFT( 15 | imgUrl: string, 16 | imageSize: '256' | '512' | '1024' = '256', 17 | ) { 18 | const url = ipfsResolverWithFallback(imgUrl); 19 | return `${COVALENT_IMG_SIZER}/width=${imageSize},fit/${url}`; 20 | } 21 | -------------------------------------------------------------------------------- /packages/common/src/utils/nfts/isNFT.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NftTokenWithBalance, 3 | TokenType, 4 | TokenWithBalance, 5 | } from '@avalabs/vm-module-types'; 6 | 7 | export function isNftTokenType(type: TokenType) { 8 | return type === TokenType.ERC721 || type === TokenType.ERC1155; 9 | } 10 | 11 | export function isNFT(token: TokenWithBalance): token is NftTokenWithBalance { 12 | return isNftTokenType(token.type); 13 | } 14 | -------------------------------------------------------------------------------- /packages/common/src/utils/nfts/nftTypesUtils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Erc1155TokenBalance, 3 | Erc721TokenBalance, 4 | ListErc1155BalancesResponse, 5 | } from '@avalabs/glacier-sdk'; 6 | 7 | export function is1155Response( 8 | item, 9 | ): item is PromiseFulfilledResult { 10 | return Object.keys(item.value).includes('erc1155TokenBalances'); 11 | } 12 | 13 | export function isErc721TokenBalance( 14 | token: Erc721TokenBalance | Erc1155TokenBalance, 15 | ): token is Erc721TokenBalance { 16 | return token.ercType === Erc721TokenBalance.ercType.ERC_721; 17 | } 18 | -------------------------------------------------------------------------------- /packages/common/src/utils/noop.ts: -------------------------------------------------------------------------------- 1 | export const noop = () => { 2 | // noop for testing puposes 3 | }; 4 | -------------------------------------------------------------------------------- /packages/common/src/utils/normalizeBalance.ts: -------------------------------------------------------------------------------- 1 | import { bnToBig } from '@avalabs/core-utils-sdk'; 2 | import type Big from 'big.js'; 3 | import { isBN } from 'bn.js'; 4 | import type BN from 'bn.js'; 5 | 6 | import { bigintToBig } from './bigintToBig'; 7 | 8 | export function normalizeBalance( 9 | balance: BN | Big | bigint | undefined, 10 | decimals: number, 11 | ): Big | undefined { 12 | if (isBN(balance)) { 13 | return bnToBig(balance, decimals); 14 | } 15 | 16 | if (typeof balance === 'bigint') { 17 | return bigintToBig(balance, decimals); 18 | } 19 | 20 | return balance; 21 | } 22 | -------------------------------------------------------------------------------- /packages/common/src/utils/number.ts: -------------------------------------------------------------------------------- 1 | export function toPrecision(num: string, precision = 4) { 2 | const [leftSide, rightSide] = num.split('.'); 3 | 4 | if (!rightSide) { 5 | return leftSide; 6 | } 7 | 8 | return `${leftSide}.${rightSide.substring(0, precision)}`; 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/utils/object.ts: -------------------------------------------------------------------------------- 1 | import { EnsureDefined, ExcludeUndefined } from '@core/types'; 2 | 3 | export const omitUndefined = >(obj: T) => 4 | Object.fromEntries( 5 | Object.entries(obj).filter(([, value]) => value !== undefined), 6 | ) as ExcludeUndefined; 7 | 8 | export const hasDefined = ( 9 | obj: T, 10 | key: K, 11 | ): obj is EnsureDefined => { 12 | return obj[key] !== undefined; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/common/src/utils/openFullscreenTab.ts: -------------------------------------------------------------------------------- 1 | import { tabs } from 'webextension-polyfill'; 2 | 3 | export const openFullscreenTab = (url: string) => { 4 | tabs.create({ 5 | url: `/fullscreen.html#/${url}`, 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/common/src/utils/promiseResolver.ts: -------------------------------------------------------------------------------- 1 | export function resolve(promise: Promise) { 2 | try { 3 | return promise.then((res) => [res, null]).catch((err) => [null, err]); 4 | } catch (err) { 5 | return Promise.resolve([null, err]); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/common/src/utils/seedPhraseValidation.ts: -------------------------------------------------------------------------------- 1 | import { Mnemonic } from 'ethers'; 2 | 3 | export const wordPhraseLength = [12, 18, 24]; 4 | 5 | export const isPhraseCorrect = (phrase: string) => { 6 | const trimmed = phrase.trim().split(/\s+/g); 7 | 8 | return ( 9 | wordPhraseLength.includes(trimmed.length) && 10 | Mnemonic.isValidMnemonic(trimmed.join(' ').toLowerCase()) 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /packages/common/src/utils/seedless/authenticateWithGoogle.ts: -------------------------------------------------------------------------------- 1 | import { launchWebAuthFlow } from './launchWebAuthFlow'; 2 | 3 | export async function authenticateWithGoogle(): Promise { 4 | const manifest = chrome.runtime.getManifest(); 5 | 6 | if (!manifest.oauth2 || !manifest.oauth2.scopes) { 7 | throw new Error('Oauth not configured'); 8 | } 9 | 10 | const redirectUri = 'https://' + chrome.runtime.id + '.chromiumapp.org'; 11 | const url = new URL('https://accounts.google.com/o/oauth2/auth'); 12 | 13 | url.searchParams.set('client_id', manifest.oauth2.client_id); 14 | url.searchParams.set('response_type', 'id_token'); 15 | url.searchParams.set('redirect_uri', redirectUri); 16 | url.searchParams.set('scope', manifest.oauth2.scopes.join(' ')); 17 | 18 | return launchWebAuthFlow(url); 19 | } 20 | -------------------------------------------------------------------------------- /packages/common/src/utils/seedless/fido/index.ts: -------------------------------------------------------------------------------- 1 | export * from './convertRequest'; 2 | export * from './convertResult'; 3 | export * from './validateResponse'; 4 | export * from './launchFidoFlow'; 5 | export * from './seedless-utils'; 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/seedless/getSignerToken.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CubeSigner, 3 | SignerSessionData, 4 | SignerSessionManager, 5 | envs, 6 | } from '@cubist-labs/cubesigner-sdk'; 7 | 8 | export const getSignerToken = async ( 9 | oidcAuthResponse: Awaited>, 10 | ): Promise => { 11 | const sessionInfo = oidcAuthResponse.data(); 12 | const sessionMgr = await SignerSessionManager.createFromSessionInfo( 13 | envs[process.env.CUBESIGNER_ENV || ''], 14 | process.env.SEEDLESS_ORG_ID || '', 15 | sessionInfo, 16 | ); 17 | 18 | return sessionMgr.storage.retrieve(); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/common/src/utils/shouldUseWalletConnectApproval.ts: -------------------------------------------------------------------------------- 1 | import { type Network, NetworkVMType } from '@avalabs/core-chains-sdk'; 2 | import { type Account, AccountType } from '@core/types'; 3 | 4 | export function shouldUseWalletConnectApproval( 5 | network: Network, 6 | account: Account, 7 | ) { 8 | // We are not supporting CoreEth as a network 9 | if (network.vmName === NetworkVMType.CoreEth) { 10 | return false; 11 | } 12 | 13 | if ( 14 | account.type === AccountType.FIREBLOCKS || 15 | account.type === AccountType.WALLET_CONNECT 16 | ) { 17 | return network.vmName === NetworkVMType.BITCOIN ? false : true; 18 | } 19 | 20 | return false; 21 | } 22 | -------------------------------------------------------------------------------- /packages/common/src/utils/stringToBigint.ts: -------------------------------------------------------------------------------- 1 | import Big from 'big.js'; 2 | 3 | export function stringToBigint(value: string, decimals: number): bigint { 4 | const big = Big(value.replace(/,/gi, '')); 5 | const tens = Big(10).pow(decimals); 6 | const mult = big.times(tens); 7 | const rawStr = mult.toFixed(0, 0); 8 | return BigInt(rawStr); 9 | } 10 | -------------------------------------------------------------------------------- /packages/common/src/utils/stripAddressPrefix.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Removes the C-, P- and X- prefix from the provided address. 3 | */ 4 | export const stripAddressPrefix = (address: string) => 5 | address.replace(/^[XPC]-/, ''); 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/sumByProperty.test.ts: -------------------------------------------------------------------------------- 1 | import { sumByProperty } from './sumByProperty'; 2 | 3 | describe('src/utils/sumByProperty.ts', () => { 4 | it('sums the numeric values held by specified property', () => { 5 | expect(sumByProperty([{ x: 1 }, { x: 2 }, { x: 3 }], 'x')).toEqual(6); 6 | expect(sumByProperty([{ x: -1 }, { x: -2 }, { x: 3 }], 'x')).toEqual(0); 7 | }); 8 | 9 | it('ignores the non-numeric values', () => { 10 | expect( 11 | sumByProperty( 12 | [{ x: 'not a number' }, { x: 2 }, { x: null }, { x: -10 }, { x: 5 }], 13 | 'x', 14 | ), 15 | ).toEqual(-3); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/common/src/utils/sumByProperty.ts: -------------------------------------------------------------------------------- 1 | import { formatAndLog } from './logging'; 2 | 3 | export const sumByProperty = , T extends keyof O>( 4 | values: O[], 5 | key: T, 6 | ): number => { 7 | return values.reduce((acc, curr, index) => { 8 | const value = curr[key]; 9 | 10 | if (typeof value === 'number') { 11 | return acc + value; 12 | } 13 | 14 | // Log out instances when provided list contains non-numeric values 15 | formatAndLog( 16 | `sumByProperty(): object at index ${index} was ignored. Property ${String( 17 | key, 18 | )} does not contain a number:`, 19 | curr, 20 | ); 21 | 22 | return acc; 23 | }, 0); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/common/src/utils/toArrayBuffer.ts: -------------------------------------------------------------------------------- 1 | export const toArrayBuffer = ( 2 | value: Buffer | Uint8Array, 3 | ): ArrayBuffer => { 4 | return Uint8Array.from(value).buffer; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/common/src/utils/truncateAddress.ts: -------------------------------------------------------------------------------- 1 | export const truncateAddress = (address: string, size = 6): string => { 2 | const firstChunk = address.substring(0, size); 3 | const lastChunk = address.substr(-(size / 2)); 4 | 5 | return `${firstChunk}...${lastChunk}`; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/common/src/utils/typeUtils.ts: -------------------------------------------------------------------------------- 1 | export const isFulfilled = ( 2 | x: PromiseSettledResult, 3 | ): x is PromiseFulfilledResult => x.status === 'fulfilled'; 4 | 5 | export const isNotNullish = (x: T): x is NonNullable => x != null; 6 | -------------------------------------------------------------------------------- /packages/common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "include": ["./src", "../types/*.d.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/content-script/README.md: -------------------------------------------------------------------------------- 1 | # content-script 2 | -------------------------------------------------------------------------------- /packages/content-script/rsbuild.content-script.dev.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, mergeRsbuildConfig } from '@rsbuild/core'; 2 | import commonConfig from './rsbuild.content-script.common'; 3 | import { getEnvVars } from '../../build-scripts/getEnvVars'; 4 | 5 | export default defineConfig((...args) => 6 | mergeRsbuildConfig(commonConfig(...args), { 7 | mode: 'development', 8 | source: { 9 | define: getEnvVars('dev'), 10 | }, 11 | }), 12 | ); 13 | -------------------------------------------------------------------------------- /packages/content-script/rsbuild.content-script.prod.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, mergeRsbuildConfig } from '@rsbuild/core'; 2 | import commonConfig from './rsbuild.content-script.common'; 3 | import { getEnvVars } from '../../build-scripts/getEnvVars'; 4 | 5 | export default defineConfig((...args) => 6 | mergeRsbuildConfig(commonConfig(...args), { 7 | mode: 'production', 8 | output: { 9 | sourceMap: { 10 | js: 'hidden-source-map', 11 | }, 12 | }, 13 | source: { 14 | define: getEnvVars('production'), 15 | }, 16 | }), 17 | ); 18 | -------------------------------------------------------------------------------- /packages/content-script/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "include": ["./src", "../types/*.d.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/inpage/README.md: -------------------------------------------------------------------------------- 1 | # inpage 2 | -------------------------------------------------------------------------------- /packages/inpage/globals.d.ts: -------------------------------------------------------------------------------- 1 | import { EVMProvider } from '@avalabs/evm-module/dist/provider'; 2 | import { MultiWalletProviderProxy } from './src/MultiWalletProviderProxy'; 3 | 4 | declare global { 5 | interface Window { 6 | avalanche?: EVMProvider; 7 | ethereum?: MultiWalletProviderProxy | EVMProvider; 8 | evmproviders?: Record; 9 | } 10 | 11 | const EVM_PROVIDER_INFO_UUID: string; 12 | const EVM_PROVIDER_INFO_NAME: string; 13 | const EVM_PROVIDER_INFO_ICON: `data:image/svg+xml;base64,${string}`; 14 | const EVM_PROVIDER_INFO_DESCRIPTION: string; 15 | const EVM_PROVIDER_INFO_RDNS: string; 16 | const CORE_EXTENSION_VERSION: string; 17 | } 18 | 19 | export {}; 20 | -------------------------------------------------------------------------------- /packages/inpage/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChainAgnosticProvider'; 2 | export * from './initializeInpageProvider'; 3 | export * from './MultiWalletProviderProxy'; 4 | export * from './models'; 5 | -------------------------------------------------------------------------------- /packages/inpage/src/models.ts: -------------------------------------------------------------------------------- 1 | import { Eip1193Provider } from 'ethers'; 2 | 3 | interface EIP6963ProviderInfo { 4 | uuid: string; 5 | name: string; 6 | icon: string; 7 | rdns: string; 8 | } 9 | 10 | export interface EIP6963ProviderDetail { 11 | info: EIP6963ProviderInfo; 12 | provider: Eip1193Provider; 13 | } 14 | 15 | export interface EIP6963AnnounceProviderEvent extends CustomEvent { 16 | type: 'eip6963:announceProvider'; 17 | detail: EIP6963ProviderDetail; 18 | } 19 | 20 | export enum EventNames { 21 | CORE_WALLET_ANNOUNCE_PROVIDER = 'core-wallet:announceProvider', 22 | CORE_WALLET_REQUEST_PROVIDER = 'core-wallet:requestProvider', 23 | EIP6963_ANNOUNCE_PROVIDER = 'eip6963:announceProvider', 24 | EIP6963_REQUEST_PROVIDER = 'eip6963:requestProvider', 25 | } 26 | -------------------------------------------------------------------------------- /packages/inpage/src/utils/onDomReady.ts: -------------------------------------------------------------------------------- 1 | export default function onDomReady(callback) { 2 | if (['interactive', 'complete'].includes(document.readyState)) { 3 | callback(); 4 | } else { 5 | document.addEventListener('DOMContentLoaded', callback, { 6 | once: true, 7 | }); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/inpage/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "include": ["./src", "globals.d.ts", "../types/*.d.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/messaging/README.md: -------------------------------------------------------------------------------- 1 | # messaging 2 | -------------------------------------------------------------------------------- /packages/messaging/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './PortConnection'; 2 | export * from './AutoPairingPostMessageConnection'; 3 | export * from './models'; 4 | export * from './AbstractConnection'; 5 | export * from './serialization'; 6 | -------------------------------------------------------------------------------- /packages/messaging/src/models.ts: -------------------------------------------------------------------------------- 1 | import { JsonRpcRequest } from '@core/types'; 2 | 3 | export type Response = { 4 | type: 'response'; 5 | id: string; 6 | res: unknown; 7 | err: unknown; 8 | }; 9 | 10 | export type Request = { 11 | type: 'request'; 12 | id: string; 13 | data: JsonRpcRequest; 14 | }; 15 | 16 | export type Message = 17 | | { 18 | type: 'message'; 19 | data: unknown; 20 | } 21 | | Request 22 | | Response; 23 | 24 | export const isResponse = (message: Message): message is Response => { 25 | return message.type === 'response'; 26 | }; 27 | 28 | export const isRequest = (message: Message): message is Request => { 29 | return message.type === 'request'; 30 | }; 31 | -------------------------------------------------------------------------------- /packages/messaging/src/serialization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './deserialize'; 2 | export * from './serialize'; 3 | -------------------------------------------------------------------------------- /packages/messaging/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "include": ["./src", "../types/*.d.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/offscreen/README.md: -------------------------------------------------------------------------------- 1 | # inpage 2 | -------------------------------------------------------------------------------- /packages/offscreen/rsbuild.offscreen.dev.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, mergeRsbuildConfig } from '@rsbuild/core'; 2 | import commonConfig from './rsbuild.offscreen.common'; 3 | import { getEnvVars } from '../../build-scripts/getEnvVars'; 4 | 5 | export default defineConfig((...args) => 6 | mergeRsbuildConfig(commonConfig(...args), { 7 | source: { 8 | define: getEnvVars('dev'), 9 | }, 10 | output: { 11 | sourceMap: { 12 | js: 'inline-source-map', 13 | }, 14 | }, 15 | }), 16 | ); 17 | -------------------------------------------------------------------------------- /packages/offscreen/rsbuild.offscreen.prod.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, mergeRsbuildConfig } from '@rsbuild/core'; 2 | import commonConfig from './rsbuild.offscreen.common'; 3 | import { getEnvVars } from '../../build-scripts/getEnvVars'; 4 | 5 | export default defineConfig((...args) => 6 | mergeRsbuildConfig(commonConfig(...args), { 7 | mode: 'production', 8 | output: { 9 | sourceMap: { 10 | js: 'hidden-source-map', 11 | }, 12 | }, 13 | source: { 14 | define: getEnvVars('production'), 15 | }, 16 | }), 17 | ); 18 | -------------------------------------------------------------------------------- /packages/offscreen/src/offscreen.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Core Extension Gasless Off Screen 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/offscreen/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "include": ["./src", "globals.d.ts", "../types/*.d.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/service-worker/README.md: -------------------------------------------------------------------------------- 1 | # service-worker 2 | -------------------------------------------------------------------------------- /packages/service-worker/__mocks__/@blockaid/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @blockaid/client runs environment checks on import. 3 | * This results in errors being thrown if it gets incluced anywhere in the dependency tree. 4 | * fetch is not available with the `jest-environment-jsdom` environment. 5 | * To avoid errors, make sure we mock this library everywhere. 6 | */ 7 | 8 | export default {}; 9 | -------------------------------------------------------------------------------- /packages/service-worker/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */ 2 | 3 | module.exports = { 4 | clearMocks: true, 5 | preset: 'ts-jest', 6 | resolver: '/../../src/tests/resolver.js', 7 | testEnvironment: 'jest-environment-jsdom', 8 | setupFilesAfterEnv: ['/../../src/tests/setupTests.ts'], 9 | moduleNameMapper: { 10 | '^~/(.*)': '/src/$1', 11 | '^@shared/(.*)': '/../../src/$1', 12 | '\\.(css|less|scss)$': 'identity-obj-proxy', 13 | '^uuid$': require.resolve('uuid'), 14 | }, 15 | transform: { 16 | '^.+\\.(js|jsx)$': 'babel-jest', 17 | }, 18 | transformIgnorePatterns: [`/node_modules/(?!micro-eth-signer)`], 19 | modulePathIgnorePatterns: ['/dist/'], 20 | }; 21 | -------------------------------------------------------------------------------- /packages/service-worker/rsbuild.worker.dev.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, mergeRsbuildConfig } from '@rsbuild/core'; 2 | import commonConfig from './rsbuild.worker.common'; 3 | import { getEnvVars } from '../../build-scripts/getEnvVars'; 4 | 5 | export default defineConfig((...args) => 6 | mergeRsbuildConfig(commonConfig(...args), { 7 | mode: 'development', 8 | source: { 9 | define: getEnvVars('dev'), 10 | }, 11 | output: { 12 | sourceMap: { 13 | js: 'inline-source-map', 14 | }, 15 | }, 16 | }), 17 | ); 18 | -------------------------------------------------------------------------------- /packages/service-worker/rsbuild.worker.prod.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, mergeRsbuildConfig } from '@rsbuild/core'; 2 | import commonConfig from './rsbuild.worker.common'; 3 | import { getEnvVars } from '../../build-scripts/getEnvVars'; 4 | 5 | export default defineConfig((...args) => 6 | mergeRsbuildConfig(commonConfig(...args), { 7 | mode: 'production', 8 | output: { 9 | sourceMap: { 10 | js: 'hidden-source-map', 11 | }, 12 | }, 13 | source: { 14 | define: getEnvVars('production'), 15 | }, 16 | }), 17 | ); 18 | -------------------------------------------------------------------------------- /packages/service-worker/src/connections/offscreenConnection/registry.ts: -------------------------------------------------------------------------------- 1 | import { GaslessSendOffscreenMessageEvent } from '../../services/gasless/events/gaslessSendMessageEvent'; 2 | import { SetGaslessHexValues } from '../../services/gasless/handlers/setHexValues'; 3 | import { registry } from 'tsyringe'; 4 | 5 | @registry([ 6 | { 7 | token: 'OffscreenRequestHandler', 8 | useToken: SetGaslessHexValues, 9 | }, 10 | ]) 11 | export class OffscreenRequestHandlerRegistry {} 12 | 13 | @registry([ 14 | { 15 | token: 'OffscreenEventEmitter', 16 | useToken: GaslessSendOffscreenMessageEvent, 17 | }, 18 | ]) 19 | export class OffscreenEventEmitterRegistry {} 20 | -------------------------------------------------------------------------------- /packages/service-worker/src/init.ts: -------------------------------------------------------------------------------- 1 | // initialize sentry first to enable error collection 2 | import './monitoring/initSentryForBackground'; 3 | import 'reflect-metadata'; 4 | import { initI18n } from '@core/common'; 5 | import { container } from 'tsyringe'; 6 | import { BackgroundRuntime } from './runtime/BackgroundRuntime'; 7 | import Big from 'big.js'; 8 | 9 | Big.PE = 99; 10 | Big.NE = -18; 11 | 12 | // Initialize translations 13 | initI18n(); 14 | 15 | const runtime = container.resolve(BackgroundRuntime); 16 | runtime.activate(); 17 | -------------------------------------------------------------------------------- /packages/service-worker/src/runtime/openApprovalWindow.ts: -------------------------------------------------------------------------------- 1 | import { container } from 'tsyringe'; 2 | 3 | import { Action, MultiTxAction } from '@core/types'; 4 | import { ApprovalService } from '../services/approvals/ApprovalService'; 5 | 6 | export const openApprovalWindow = async ( 7 | action: Action | MultiTxAction, 8 | url: string, 9 | ) => { 10 | const actionId = crypto.randomUUID(); 11 | // using direct injection instead of the constructor to prevent circular dependencies 12 | const approvalService = container.resolve(ApprovalService); 13 | 14 | return approvalService.requestApproval( 15 | { 16 | ...action, 17 | actionId, 18 | }, 19 | url, 20 | ); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/actions/utils.ts: -------------------------------------------------------------------------------- 1 | import browser from 'webextension-polyfill'; 2 | import { Actions } from '@core/types'; 3 | 4 | /** 5 | * Filters out actions from the actions list without an open window 6 | */ 7 | export async function filterStaleActions( 8 | actionsInStorage: Actions, 9 | ): Promise { 10 | const openWindowIds = (await browser.windows.getAll()) 11 | .filter((w) => w.type === 'popup') 12 | .map((w) => w.id); 13 | 14 | return Object.keys(actionsInStorage).reduce((acc, actionId) => { 15 | const action = actionsInStorage[actionId]; 16 | if ( 17 | action?.popupWindowId && 18 | openWindowIds.includes(action?.popupWindowId) 19 | ) { 20 | return { ...acc, [actionId]: action }; 21 | } 22 | return {}; 23 | }, {}); 24 | } 25 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/analytics/handlers/clearAnalyticsIds.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionRequest, ExtensionRequestHandler } from '@core/types'; 2 | import { injectable } from 'tsyringe'; 3 | import { AnalyticsService } from '../AnalyticsService'; 4 | 5 | type HandlerType = ExtensionRequestHandler< 6 | ExtensionRequest.ANALYTICS_CLEAR_IDS, 7 | true 8 | >; 9 | 10 | @injectable() 11 | export class ClearAnalyticsIdsHandler implements HandlerType { 12 | method = ExtensionRequest.ANALYTICS_CLEAR_IDS as const; 13 | 14 | constructor(private analyticsService: AnalyticsService) {} 15 | 16 | handle: HandlerType['handle'] = async ({ request }) => { 17 | await this.analyticsService.clearIds(); 18 | 19 | return { 20 | ...request, 21 | result: true, 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/appcheck/utils/challenges/reverse.test.ts: -------------------------------------------------------------------------------- 1 | import solveReverseChallenge from './reverse'; 2 | 3 | describe('reverse', () => { 4 | beforeEach(() => { 5 | jest.resetAllMocks(); 6 | }); 7 | 8 | it('throws when params are incorrect', () => { 9 | expect(() => solveReverseChallenge('{}')).toThrow( 10 | 'invalid reverse challenge details', 11 | ); 12 | }); 13 | 14 | it('solves the challenge correctly', () => { 15 | const details = { 16 | token: 'abde8a8173a35ddb5aa34abc0d7efe7293d9f365732d6a109a6aa2add64bb0df', 17 | }; 18 | 19 | expect(solveReverseChallenge(JSON.stringify(details))).toBe( 20 | 'fd0bb46dda2aa6a901a6d237563f9d3927efe7d0cba43aa5bdd53a3718a8edba', 21 | ); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/appcheck/utils/getHashByAlgorithm.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from 'crypto'; 2 | import { Algorithm } from '@core/types'; 3 | 4 | const getHashByAlgorithm = (algorithm: Algorithm, data: string) => { 5 | switch (algorithm) { 6 | case Algorithm.SHA256: 7 | return createHash('sha256').update(data).digest('hex'); 8 | case Algorithm.SHA512: 9 | return createHash('sha512').update(data).digest('hex'); 10 | default: 11 | throw new Error(`unsupported algorithm "${algorithm}"`); 12 | } 13 | }; 14 | 15 | export default getHashByAlgorithm; 16 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/appcheck/utils/solveChallenge.ts: -------------------------------------------------------------------------------- 1 | import { ChallengeSolver, ChallengeTypes } from '@core/types'; 2 | import solveBasicChallenge from './challenges/basic'; 3 | import solveReverseChallenge from './challenges/reverse'; 4 | 5 | type Params = { 6 | type: ChallengeTypes; 7 | challengeDetails: string; 8 | }; 9 | 10 | const CHALLENGE_MAP: Record = { 11 | [ChallengeTypes.BASIC]: solveBasicChallenge, 12 | [ChallengeTypes.REVERSE]: solveReverseChallenge, 13 | }; 14 | 15 | const solveChallenge = async ({ type, challengeDetails }: Params) => { 16 | const solver = CHALLENGE_MAP[type]; 17 | return solver(challengeDetails); 18 | }; 19 | 20 | export default solveChallenge; 21 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/balances/handlers/getTotalBalanceForWallet/helpers/calculateTotalBalanceForAccounts.ts: -------------------------------------------------------------------------------- 1 | import { Account, Balances, NetworkWithCaipId } from '@core/types'; 2 | import { calculateTotalBalance } from '@core/common'; 3 | 4 | export function calculateTotalBalanceForAccounts( 5 | balances: Balances, 6 | accounts: Partial[], 7 | networks: NetworkWithCaipId[], 8 | ): number { 9 | return accounts.reduce((sum: number, account: Partial) => { 10 | const accountBalance = calculateTotalBalance(account, networks, balances); 11 | return sum + (accountBalance.sum ?? 0); 12 | }, 0); 13 | } 14 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/balances/handlers/getTotalBalanceForWallet/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './calculateTotalBalanceForAccounts'; 2 | export * from './getAccountsWithActivity'; 3 | export * from './getIncludedNetworks'; 4 | export * from './isDone'; 5 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/balances/handlers/getTotalBalanceForWallet/helpers/isDone.test.ts: -------------------------------------------------------------------------------- 1 | import { ADDRESS_GAP_LIMIT } from '../models'; 2 | import { isDone } from './isDone'; 3 | 4 | describe('src/background/services/balances/handlers/getTotalBalanceForWallet/helpers/isDone', () => { 5 | it(`returns false beyond ${ADDRESS_GAP_LIMIT}`, () => { 6 | expect(isDone(ADDRESS_GAP_LIMIT - 1)).toBe(false); 7 | expect(isDone(ADDRESS_GAP_LIMIT)).toBe(false); 8 | expect(isDone(ADDRESS_GAP_LIMIT + 1)).toBe(true); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/balances/handlers/getTotalBalanceForWallet/helpers/isDone.ts: -------------------------------------------------------------------------------- 1 | import { ADDRESS_GAP_LIMIT } from '../models'; 2 | 3 | export function isDone(currentGap: number) { 4 | return currentGap > ADDRESS_GAP_LIMIT; 5 | } 6 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/balances/handlers/getTotalBalanceForWallet/index.ts: -------------------------------------------------------------------------------- 1 | import { GetTotalBalanceForWalletHandler } from './getTotalBalanceForWallet'; 2 | 3 | export { GetTotalBalanceForWalletHandler }; 4 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/balances/handlers/getTotalBalanceForWallet/models.ts: -------------------------------------------------------------------------------- 1 | import { ChainAddressChainIdMapListResponse } from '@avalabs/glacier-sdk'; 2 | import { IMPORTED_ACCOUNTS_WALLET_ID } from '@core/types'; 3 | 4 | export type GetTotalBalanceForWalletParams = { 5 | walletId: string; 6 | }; 7 | 8 | export type AddressActivityFetcher = ( 9 | addresses: string[], 10 | ) => Promise; 11 | 12 | export const ITERATION_LIMIT = 10; // Abitrary number to avoid an infinite loop. 13 | export const ADDRESS_GAP_LIMIT = 20; 14 | export const GLACIER_ADDRESS_FETCH_LIMIT = 64; // Requested addresses are encoded as query params, and Glacier enforces URI length limits 15 | 16 | export const isImportedAccountsRequest = (walletId: string) => 17 | walletId === IMPORTED_ACCOUNTS_WALLET_ID; 18 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/bridge/events/listeners.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ava-labs/core-extension/8f21ff2dafbc3ea07c40111a173a1041657cddff/packages/service-worker/src/services/bridge/events/listeners.ts -------------------------------------------------------------------------------- /packages/service-worker/src/services/bridge/handlers/getBridgeState.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BridgeState, 3 | ExtensionRequest, 4 | ExtensionRequestHandler, 5 | } from '@core/types'; 6 | import { injectable } from 'tsyringe'; 7 | import { BridgeService } from '../BridgeService'; 8 | 9 | type HandlerType = ExtensionRequestHandler< 10 | ExtensionRequest.BRIDGE_GET_STATE, 11 | BridgeState 12 | >; 13 | 14 | @injectable() 15 | export class BridgeGetStateHandler implements HandlerType { 16 | method = ExtensionRequest.BRIDGE_GET_STATE as const; 17 | 18 | constructor(private bridgeService: BridgeService) {} 19 | 20 | handle: HandlerType['handle'] = async ({ request }) => { 21 | return { 22 | ...request, 23 | result: this.bridgeService.bridgeState, 24 | }; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/currency/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CurrencyService'; 2 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/debank/fixtures/chain_list.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "avax", 4 | "community_id": 43114, 5 | "name": "Avalanche", 6 | "native_token_id": "avax", 7 | "logo_url": "https://static.debank.com/image/chain/logo_url/avax/4d1649e8a0c7dec9de3491b81807d402.png", 8 | "wrapped_token_id": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7", 9 | "is_support_pre_exec": true 10 | }, 11 | { 12 | "id": "eth", 13 | "community_id": 1, 14 | "name": "Ethereum", 15 | "native_token_id": "eth", 16 | "logo_url": "https://static.debank.com/image/chain/logo_url/eth/42ba589cd077e7bdd97db6480b0ff61d.png", 17 | "wrapped_token_id": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", 18 | "is_support_pre_exec": false 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/debank/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DebankService'; 2 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/debank/utils/mapTokenItemToTransactionToken.ts: -------------------------------------------------------------------------------- 1 | import Big from 'big.js'; 2 | import { DebankTokenItem, TransactionToken } from '@core/types'; 3 | import { bigToBigInt } from '@avalabs/core-utils-sdk'; 4 | 5 | export const mapTokenItemToTransactionToken = ( 6 | t: DebankTokenItem, 7 | ): TransactionToken => ({ 8 | address: t.id, 9 | decimals: t.decimals, 10 | symbol: t.symbol, 11 | name: t.name, 12 | logoUri: t.logo_url, 13 | 14 | amount: bigToBigInt(Big(t.amount), t.decimals), 15 | usdValue: t.usd_value, 16 | usdPrice: t.price, 17 | 18 | isScam: t.is_scam, 19 | isInfinity: t.is_infinity, 20 | isSuspicious: t.is_suspicious, 21 | }); 22 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/debank/utils/txParamsToTransactionData.ts: -------------------------------------------------------------------------------- 1 | import { toBeHex } from 'ethers'; 2 | import { Network } from '@avalabs/core-chains-sdk'; 3 | import { DebankTransactionData, EthSendTransactionParams } from '@core/types'; 4 | 5 | export function txParamsToTransactionData( 6 | network: Network, 7 | tx: EthSendTransactionParams, 8 | ): DebankTransactionData { 9 | return { 10 | from: tx.from, 11 | to: tx.to ?? '0x', 12 | data: tx.data ?? '0x', 13 | value: tx.value ? toBeHex(tx.value) : '0x', 14 | chainId: network.chainId, 15 | gas: `0x${BigInt(tx.gas ?? 0).toString(16)}`, 16 | nonce: tx.nonce ? tx.nonce : `0x1`, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/fireblocks/models.ts: -------------------------------------------------------------------------------- 1 | // import type { KeyLike } from 'jose'; 2 | 3 | export abstract class FireblocksSecretsProvider { 4 | abstract getSecrets(): Promise<{ apiKey: string; privateKey: any }>; 5 | } 6 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/fireblocks/registry.ts: -------------------------------------------------------------------------------- 1 | import { registry } from 'tsyringe'; 2 | 3 | import { FireblocksSecretsService } from './FireblocksSecretsService'; 4 | 5 | @registry([ 6 | { token: 'FireblocksSecretsProvider', useToken: FireblocksSecretsService }, 7 | ]) 8 | export class FireblocksRegistry {} 9 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/glacier/glacierConfig.ts: -------------------------------------------------------------------------------- 1 | import { AppName } from '@avalabs/vm-module-types'; 2 | import { runtime } from 'webextension-polyfill'; 3 | 4 | export const HEADERS = { 5 | 'x-application-name': AppName.CORE_EXTENSION, 6 | 'x-application-version': runtime.getManifest().version, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/keystone/utils.ts: -------------------------------------------------------------------------------- 1 | import { TxData } from '@ethereumjs/tx'; 2 | import { BufferLike } from 'ethereumjs-util'; 3 | import { TransactionRequest } from 'ethers'; 4 | 5 | import { makeBNLike } from '@core/common'; 6 | 7 | /** 8 | * Convert tx data from `TransactionRequest` (ethers) to `TxData` (@ethereumjs) 9 | */ 10 | export function convertTxData(txData: TransactionRequest): TxData { 11 | return { 12 | to: txData.to?.toString(), 13 | nonce: makeBNLike(txData.nonce), 14 | gasPrice: makeBNLike(txData.gasPrice), 15 | gasLimit: makeBNLike(txData.gasLimit), 16 | value: makeBNLike(txData.value), 17 | data: txData.data as BufferLike, 18 | type: makeBNLike(txData.type), 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/ledger/handlers/closeOpenTransporters.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionRequest, ExtensionRequestHandler } from '@core/types'; 2 | import { injectable } from 'tsyringe'; 3 | import { LedgerService } from '../LedgerService'; 4 | 5 | type HandlerType = ExtensionRequestHandler< 6 | ExtensionRequest.LEDGER_CLOSE_TRANSPORT, 7 | true, 8 | [] 9 | >; 10 | 11 | @injectable() 12 | export class CloseLedgerTransportHandler implements HandlerType { 13 | method = ExtensionRequest.LEDGER_CLOSE_TRANSPORT as const; 14 | 15 | constructor(private ledgerService: LedgerService) {} 16 | 17 | handle: HandlerType['handle'] = async ({ request }) => { 18 | await this.ledgerService.closeOpenedTransport(); 19 | return { 20 | result: true, 21 | ...request, 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/lock/handlers/getLockState.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionRequest, ExtensionRequestHandler } from '@core/types'; 2 | import { injectable } from 'tsyringe'; 3 | import { LockService } from '../LockService'; 4 | 5 | type HandlerType = ExtensionRequestHandler< 6 | ExtensionRequest.LOCK_GET_STATE, 7 | boolean 8 | >; 9 | 10 | @injectable() 11 | export class GetLockStateHandler implements HandlerType { 12 | method = ExtensionRequest.LOCK_GET_STATE as const; 13 | 14 | constructor(private lockService: LockService) {} 15 | 16 | handle: HandlerType['handle'] = async ({ request }) => { 17 | return { 18 | ...request, 19 | result: this.lockService.locked, 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/lock/handlers/lockWallet.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionRequest, ExtensionRequestHandler } from '@core/types'; 2 | import { injectable } from 'tsyringe'; 3 | import { LockService } from '../LockService'; 4 | 5 | type HandlerType = ExtensionRequestHandler; 6 | 7 | @injectable() 8 | export class LockWalletHandler implements HandlerType { 9 | method = ExtensionRequest.LOCK_WALLET as const; 10 | 11 | constructor(private lockService: LockService) {} 12 | 13 | handle: HandlerType['handle'] = async ({ request }) => { 14 | this.lockService.lock(); 15 | 16 | return { 17 | ...request, 18 | result: true, 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/messages/utils/personalSigRecovery.ts: -------------------------------------------------------------------------------- 1 | import { recoverPersonalSignature } from '@metamask/eth-sig-util'; 2 | 3 | /** 4 | * Gets the "from" address from the data and the signed result . 5 | */ 6 | export function personalSigRecovery(msg: string, signedResult: string): string { 7 | const recoveredAddress = recoverPersonalSignature({ 8 | data: msg, 9 | signature: signedResult, 10 | }); 11 | return recoveredAddress; 12 | } 13 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/notifications/utils/getNotificationCategory.ts: -------------------------------------------------------------------------------- 1 | import { NOTIFICATION_CATEGORIES } from '../constants'; 2 | import { NotificationCategories, NotificationTypes } from '@core/types'; 3 | 4 | export const getNotificationCategory = ( 5 | notificationType: NotificationTypes, 6 | ) => { 7 | const [category] = 8 | Object.entries(NOTIFICATION_CATEGORIES).find(([_, events]) => 9 | events.includes(notificationType), 10 | ) ?? []; 11 | 12 | if (!category) { 13 | throw new Error(`Unknown notification type: ${notificationType}`); 14 | } 15 | 16 | return category as NotificationCategories; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/onboarding/handlers/getIsOnBoarded.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionRequest, 3 | ExtensionRequestHandler, 4 | OnboardingState, 5 | } from '@core/types'; 6 | import { injectable } from 'tsyringe'; 7 | import { OnboardingService } from '../OnboardingService'; 8 | type HandlerType = ExtensionRequestHandler< 9 | ExtensionRequest.ONBOARDING_GET_STATE, 10 | OnboardingState 11 | >; 12 | 13 | @injectable() 14 | export class GetIsOnboardedHandler implements HandlerType { 15 | method = ExtensionRequest.ONBOARDING_GET_STATE as const; 16 | 17 | constructor(private onboardingService: OnboardingService) {} 18 | 19 | handle: HandlerType['handle'] = async ({ request }) => { 20 | return { 21 | ...request, 22 | result: await this.onboardingService.getState(), 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/permissions/handlers/wallet_getPermissions.ts: -------------------------------------------------------------------------------- 1 | import { DAppProviderRequest, DAppRequestHandler } from '@core/types'; 2 | import { injectable } from 'tsyringe'; 3 | 4 | @injectable() 5 | export class WalletGetPermissionsHandler extends DAppRequestHandler { 6 | methods = [DAppProviderRequest.WALLET_GET_PERMISSIONS]; 7 | 8 | handleUnauthenticated = async ({ request }) => { 9 | return { 10 | ...request, 11 | result: [], 12 | }; 13 | }; 14 | handleAuthenticated = async ({ request }) => { 15 | return { 16 | ...request, 17 | result: [ 18 | { 19 | invoker: request.site.domain, 20 | parentCapability: 'accounts', 21 | }, 22 | ], 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/secrets/utils/getAccountPrivateKeyFromMnemonic.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DerivationPath, 3 | getWalletFromMnemonic, 4 | } from '@avalabs/core-wallets-sdk'; 5 | 6 | export function getAccountPrivateKeyFromMnemonic( 7 | mnemonic: string, 8 | accountIndex: number, 9 | derivationPath: DerivationPath, 10 | ): string { 11 | const signer = getWalletFromMnemonic(mnemonic, accountIndex, derivationPath); 12 | if (!signer || !signer.path) { 13 | throw new Error('The requested path is missing'); 14 | } 15 | 16 | return signer.privateKey; 17 | } 18 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/storage/schemaMigrations/migrations/wallet_storage_encryption_key_v2.ts: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | const VERSION = 2; 4 | 5 | type PreviousSchema = string; 6 | 7 | const previousSchema = Joi.string(); 8 | 9 | const up = async (storageKey: PreviousSchema) => { 10 | return { 11 | // No need to change the storageKey 12 | // We only want to trigger a re-save which will save the key with the updated key derviation algorithm 13 | storageKey, 14 | version: VERSION, 15 | }; 16 | }; 17 | 18 | export default { 19 | previousSchema, 20 | up, 21 | }; 22 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/storage/schemaMigrations/migrations/wallet_v4/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './wallet_v4'; 2 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/storage/schemaMigrations/migrations/wallet_v5/commonSchemas.ts: -------------------------------------------------------------------------------- 1 | import Joi from 'joi'; 2 | 3 | import { BtcWalletPolicyDetails, PubKeyType } from './commonModels'; 4 | 5 | export const btcWalletPolicyDetailsSchema = Joi.object< 6 | BtcWalletPolicyDetails, 7 | true 8 | >({ 9 | hmacHex: Joi.string().required(), 10 | masterFingerprint: Joi.string().required(), 11 | name: Joi.string().required(), 12 | xpub: Joi.string().required(), 13 | }); 14 | 15 | export const pubKeyTypeSchema = Joi.object({ 16 | evm: Joi.string().required(), 17 | xp: Joi.string().optional(), 18 | ed25519: Joi.string().optional(), 19 | btcWalletPolicyDetails: btcWalletPolicyDetailsSchema.optional(), 20 | }).unknown(); 21 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/tokens/utils/isTokenSupported.ts: -------------------------------------------------------------------------------- 1 | import { Network } from '@avalabs/core-chains-sdk'; 2 | import { SettingsState } from '@core/types'; 3 | 4 | export async function isTokenSupported( 5 | tokenAddress: string, 6 | network: Network, 7 | settings: SettingsState, 8 | ) { 9 | const tokenExistInNetwork = network.tokens?.find( 10 | (token) => token.address.toLowerCase() === tokenAddress.toLowerCase(), 11 | ); 12 | return ( 13 | tokenExistInNetwork || 14 | settings.customTokens[network.chainId]?.[tokenAddress.toLowerCase()] 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/unifiedBridge/handlers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './unifiedBridgeGetState'; 2 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/wallet/utils/getAddressByVM.ts: -------------------------------------------------------------------------------- 1 | import { AVM, EVM, PVM, VM } from '@avalabs/avalanchejs'; 2 | import { Account } from '@core/types'; 3 | 4 | const getAddressByVM = (vm: VM, account?: Account) => { 5 | if (!account) { 6 | return; 7 | } 8 | 9 | if (vm === AVM) { 10 | return account.addressAVM; 11 | } else if (vm === PVM) { 12 | return account.addressPVM; 13 | } else if (vm === EVM) { 14 | return account.addressCoreEth; 15 | } 16 | }; 17 | 18 | export default getAddressByVM; 19 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/wallet/utils/getDerivationPath.ts: -------------------------------------------------------------------------------- 1 | import { DerivationPath } from '@avalabs/core-wallets-sdk'; 2 | import { SignerSessionData } from '@cubist-labs/cubesigner-sdk'; 3 | import { PubKeyType } from '@core/types'; 4 | 5 | const getDerivationPath = ({ 6 | mnemonic, 7 | xpub, 8 | pubKeys, 9 | seedlessSignerToken, 10 | }: { 11 | xpub?: string; 12 | pubKeys?: PubKeyType[]; 13 | mnemonic?: string; 14 | seedlessSignerToken?: SignerSessionData; 15 | }) => { 16 | if (mnemonic || xpub || seedlessSignerToken) { 17 | return DerivationPath.BIP44; 18 | } 19 | 20 | if (pubKeys?.length) { 21 | return DerivationPath.LedgerLive; 22 | } 23 | 24 | throw new Error('Unable to get derivation type for wallet'); 25 | }; 26 | 27 | export default getDerivationPath; 28 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/wallet/utils/getProvidedUtxos.ts: -------------------------------------------------------------------------------- 1 | import { Utxo, VM, utils } from '@avalabs/avalanchejs'; 2 | 3 | type Param = { 4 | utxoHexes?: string[]; 5 | vm: VM; 6 | }; 7 | 8 | const getProvidedUtxos = ({ utxoHexes = [], vm }: Param) => { 9 | try { 10 | const codec = utils.getManagerForVM(vm).getDefaultCodec(); 11 | return utxoHexes.map((utxoHex) => { 12 | const utxoBytes = utils.hexToBuffer(utxoHex); 13 | return Utxo.fromBytes(utxoBytes, codec)[0]; 14 | }); 15 | } catch (_err) { 16 | return []; 17 | } 18 | }; 19 | 20 | export default getProvidedUtxos; 21 | -------------------------------------------------------------------------------- /packages/service-worker/src/services/web3/handlers/avalanche_sendDomainMetadata.ts: -------------------------------------------------------------------------------- 1 | import { DAppRequestHandler, DAppProviderRequest } from '@core/types'; 2 | import { injectable } from 'tsyringe'; 3 | 4 | /** 5 | * This handler is an empty request handler to fit into the regular flow of rpc calls. 6 | * The DOMAIN_METADATA requests are stored and handled in the SiteMetadataMiddleware. 7 | */ 8 | @injectable() 9 | export class AvalancheSendDomainMetadataHandler extends DAppRequestHandler { 10 | methods = [DAppProviderRequest.DOMAIN_METADATA_METHOD]; 11 | 12 | handleUnauthenticated = async ({ request }) => { 13 | return { ...request, result: request.params }; 14 | }; 15 | 16 | handleAuthenticated = async (request) => { 17 | return this.handleUnauthenticated(request); 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /packages/service-worker/src/vmModules/models.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApprovalParams, 3 | BatchApprovalParams, 4 | RpcRequest, 5 | } from '@avalabs/vm-module-types'; 6 | 7 | type RpcRequestWithExtensionContext = RpcRequest & { 8 | context?: RpcRequest['context'] & { 9 | tabId?: number; 10 | }; 11 | }; 12 | export interface MultiApprovalParamsWithContext extends BatchApprovalParams { 13 | request: RpcRequestWithExtensionContext; 14 | } 15 | export interface ApprovalParamsWithContext extends ApprovalParams { 16 | request: RpcRequestWithExtensionContext; 17 | } 18 | 19 | export const isBatchApprovalParams = ( 20 | params: ApprovalParams | BatchApprovalParams, 21 | ): params is BatchApprovalParams => { 22 | return 'signingRequests' in params; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/service-worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "~/*": ["./src/*"], 6 | "@shared/*": ["../../src/*"] 7 | } 8 | }, 9 | "include": ["./src", "../types/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core/tsconfig", 3 | "private": true, 4 | "type": "module", 5 | "files": [ 6 | "tsconfig.base.json" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /packages/types/README.md: -------------------------------------------------------------------------------- 1 | # types 2 | -------------------------------------------------------------------------------- /packages/types/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.jpg' { 2 | const value: any; 3 | export default value; 4 | } 5 | 6 | declare module '*.png' { 7 | const value: any; 8 | export default value; 9 | } 10 | -------------------------------------------------------------------------------- /packages/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@core/types", 3 | "packageManager": "yarn@4.7.0", 4 | "private": true, 5 | "main": "src/index.ts", 6 | "devDependencies": { 7 | "fireblocks-sdk": "5.20.0", 8 | "joi": "17.7.0", 9 | "jose": "4.15.5" 10 | }, 11 | "files": [ 12 | "src", 13 | "webextension-polyfill.d.ts", 14 | "images.d.ts", 15 | "types.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/types/src/app-check.ts: -------------------------------------------------------------------------------- 1 | import * as Sentry from '@sentry/browser'; 2 | 3 | export type ChallengeRequest = { 4 | id: string; 5 | tracker: Sentry.Transaction; 6 | registrationId?: string; 7 | solution?: string; 8 | }; 9 | 10 | export type ChallengeSolver = (details: string) => string | Promise; 11 | 12 | export enum Algorithm { 13 | SHA256 = 'SHA256', 14 | SHA512 = 'SHA512', 15 | } 16 | 17 | export enum ChallengeTypes { 18 | BASIC = 'BASIC', 19 | REVERSE = 'REVERSE', 20 | } 21 | 22 | export type AppCheckRegistrationChallenge = { 23 | requestId: string; 24 | registrationId: string; 25 | type: ChallengeTypes; 26 | event: string; 27 | details: string; 28 | }; 29 | -------------------------------------------------------------------------------- /packages/types/src/approvals.ts: -------------------------------------------------------------------------------- 1 | import { Action, MultiTxAction } from './actions'; 2 | 3 | export type ApprovalRequest = { 4 | action: Action | MultiTxAction; 5 | url: string; 6 | }; 7 | 8 | export enum ApprovalEvent { 9 | ApprovalRequested = 'approval-requested', 10 | } 11 | -------------------------------------------------------------------------------- /packages/types/src/contacts.ts: -------------------------------------------------------------------------------- 1 | import type { Contact } from '@avalabs/types'; 2 | 3 | export interface ContactsState { 4 | contacts: Contact[]; 5 | } 6 | 7 | export enum ContactsEvents { 8 | CONTACTS_UPDATED = 'ContactsEvents: CONTACTS_UPDATED', 9 | } 10 | 11 | export const CONTACTS_STORAGE_KEY = 'contacts'; 12 | -------------------------------------------------------------------------------- /packages/types/src/domain-metadata.ts: -------------------------------------------------------------------------------- 1 | export interface DomainMetadataRequest { 2 | method: 'avalanche_sendDomainMetadata'; 3 | params: DomainMetadata; 4 | } 5 | 6 | export interface DomainMetadata { 7 | domain: string; 8 | name?: string; 9 | icon?: string; 10 | tabId?: number; 11 | url?: string; 12 | } 13 | -------------------------------------------------------------------------------- /packages/types/src/firebase.ts: -------------------------------------------------------------------------------- 1 | import { MessagePayload } from 'firebase/messaging'; 2 | import { Content, GenerationConfig, Part, Tool } from 'firebase/vertexai'; 3 | 4 | export enum FirebaseEvents { 5 | FCM_INITIALIZED = 'FCM_INITIALIZED', 6 | FCM_TERMINATED = 'FCM_TERMINATED', 7 | } 8 | 9 | export type FcmMessageListener = ( 10 | payload: MessagePayload, 11 | ) => unknown | Promise; 12 | 13 | export interface ConfigParams { 14 | tools?: Tool[]; 15 | systemInstruction?: string | Part | Content; 16 | } 17 | export interface ChatConfig extends ConfigParams { 18 | generationConfig: GenerationConfig; 19 | } 20 | 21 | export interface ChatDialogHistory { 22 | role: 'model' | 'user'; 23 | content: string; 24 | } 25 | -------------------------------------------------------------------------------- /packages/types/src/history.ts: -------------------------------------------------------------------------------- 1 | import { AnalyzeTxResult } from '@avalabs/bridge-unified'; 2 | import { NetworkVMType, Transaction } from '@avalabs/vm-module-types'; 3 | 4 | export interface TxHistoryItem extends Transaction { 5 | bridgeAnalysis: AnalyzeTxResult; 6 | vmType?: VMType; 7 | } 8 | -------------------------------------------------------------------------------- /packages/types/src/keystone.ts: -------------------------------------------------------------------------------- 1 | export interface KeystoneSendState { 2 | txId: string; 3 | signature: string; 4 | } 5 | 6 | export type CBOR = { 7 | cbor: string; 8 | type: string; 9 | }; 10 | 11 | export type KeystoneDeviceRequestData = CBOR & { 12 | requestId: string; 13 | tabId?: number; 14 | }; 15 | 16 | export type KeystoneDeviceResponseData = CBOR & { 17 | requestId: string; 18 | }; 19 | 20 | export enum KeystoneEvent { 21 | DEVICE_REQUEST = 'KeystoneEvent:device_request', 22 | } 23 | 24 | export interface KeystoneTransport { 25 | requestSignature(cbor: CBOR, tabId?: number): Promise; 26 | } 27 | -------------------------------------------------------------------------------- /packages/types/src/lock.ts: -------------------------------------------------------------------------------- 1 | export const SESSION_AUTH_DATA_KEY = 'SESSION_AUTH_DATA_KEY'; 2 | export interface SessionAuthData { 3 | password: string; 4 | loginTime: number; 5 | } 6 | 7 | export const LOCK_TIMEOUT = 1000 * 60 * 60 * 12; // 12 hours 8 | export enum LockEvents { 9 | LOCK_STATE_CHANGED = 'LockServiceEvents:Lock', 10 | } 11 | 12 | export enum AlarmsEvents { 13 | AUTO_LOCK = 'auto-lock', 14 | } 15 | 16 | export interface LockStateChangedEventPayload { 17 | isUnlocked: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /packages/types/src/navigation-history.ts: -------------------------------------------------------------------------------- 1 | import * as H from 'history'; 2 | 3 | export interface NavigationHistoryDataState { 4 | [key: string]: unknown; 5 | } 6 | 7 | export type NavigationHistoryState = H.History | Record; 8 | 9 | export interface NavigationHistoryStorage { 10 | state: NavigationHistoryState; 11 | data: NavigationHistoryDataState; 12 | } 13 | 14 | export const NAVIGATION_HISTORY_STORAGE_KEY = 'NAVIGATION_HISTORY'; 15 | -------------------------------------------------------------------------------- /packages/types/src/network-fee.ts: -------------------------------------------------------------------------------- 1 | export type FeeRate = { 2 | maxFeePerGas: bigint; 3 | maxPriorityFeePerGas?: bigint; 4 | }; 5 | 6 | export interface NetworkFee { 7 | displayDecimals: number; 8 | baseFee?: bigint; 9 | low: FeeRate; 10 | medium: FeeRate; 11 | high: FeeRate; 12 | isFixedFee: boolean; 13 | } 14 | 15 | export type TransactionPriority = 'low' | 'medium' | 'high'; 16 | 17 | export type SerializedNetworkFee = Omit< 18 | NetworkFee, 19 | 'low' | 'medium' | 'high' 20 | > & { 21 | low: bigint; 22 | medium: bigint; 23 | high: bigint; 24 | isFixedFee: boolean; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/types/src/permissions.ts: -------------------------------------------------------------------------------- 1 | import { NetworkVMType } from '@avalabs/vm-module-types'; 2 | 3 | export interface DappPermissions { 4 | domain: string; 5 | accounts: { 6 | [address: string]: NetworkVMType; 7 | }; 8 | } 9 | 10 | export interface Permissions { 11 | [domain: string]: DappPermissions; 12 | } 13 | 14 | export interface PermissionsState { 15 | permissions: Permissions; 16 | } 17 | 18 | export enum PermissionEvents { 19 | PERMISSIONS_STATE_UPDATE = 'permissions-state-updated', 20 | } 21 | 22 | export const PERMISSION_STORAGE_KEY = 'permissions'; 23 | -------------------------------------------------------------------------------- /packages/types/src/storage.ts: -------------------------------------------------------------------------------- 1 | export const WALLET_STORAGE_ENCRYPTION_KEY = 'WALLET_STORAGE_ENCRYPTION_KEY'; 2 | 3 | export interface WalletStorageEncryptionKeyData { 4 | storageKey: string; 5 | } 6 | 7 | export enum KeyDerivationVersion { 8 | V1 = 'V1', 9 | V2 = 'V2', 10 | } 11 | 12 | export interface EncryptedData { 13 | cypher: number[]; 14 | nonce: number[]; 15 | salt?: number[]; 16 | keyDerivationVersion?: KeyDerivationVersion; 17 | } 18 | 19 | export interface UnencryptedData { 20 | data: T; 21 | } 22 | -------------------------------------------------------------------------------- /packages/types/src/ui.ts: -------------------------------------------------------------------------------- 1 | export enum ContextContainer { 2 | POPUP = '/popup.html', // this is extension when it opens 3 | CONFIRM = '/confirm.html', // this is used for confirms from dApps 4 | HOME = '/home.html', // This is used for tabs where the wallet is opened 5 | FULLSCREEN = '/fullscreen.html', // This is used for flows that are performed in a full tab (i.e. first ledger connection, seedless MFA setups, etc.) 6 | } 7 | -------------------------------------------------------------------------------- /packages/types/src/web3.ts: -------------------------------------------------------------------------------- 1 | export enum WalletExtensionType { 2 | CORE = 'CORE', 3 | METAMASK = 'METAMASK', 4 | UNKNOWN = 'UNKNOWN', 5 | RABBY = 'RABBY', 6 | COINBASE = 'COINBASE', 7 | PHANTOM = 'PHANTOM', 8 | ZERION = 'ZERION', 9 | KEPLR = 'KEPLR', 10 | } 11 | -------------------------------------------------------------------------------- /packages/types/types.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // workaround until TS 4.6 4 | // https://github.com/denoland/deno/issues/12754 5 | declare global { 6 | interface Crypto { 7 | randomUUID: () => `${string}-${string}-${string}-${string}-${string}`; 8 | getRandomValues: (array: T) => T; 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /packages/ui/__mocks__/@blockaid/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @blockaid/client runs environment checks on import. 3 | * This results in errors being thrown if it gets incluced anywhere in the dependency tree. 4 | * fetch is not available with the `jest-environment-jsdom` environment. 5 | * To avoid errors, make sure we mock this library everywhere. 6 | */ 7 | 8 | export default {}; 9 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/AccountsProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './AccountsProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/AccountsProvider/isAccountsUpdatedEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Accounts, 3 | AccountsEvents, 4 | ExtensionConnectionEvent, 5 | } from '@core/types'; 6 | 7 | export function isAccountsUpdatedEvent( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === AccountsEvents.ACCOUNTS_UPDATED; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/AnalyticsProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './AnalyticsProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/AnalyticsProvider/isAnalyticsStateUpdatedEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AnalyticsEvents, 3 | AnalyticsState, 4 | ExtensionConnectionEvent, 5 | } from '@core/types'; 6 | 7 | export function isAnalyticsStateUpdatedEvent( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === AnalyticsEvents.ANALYTICS_STATE_UPDATED; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/ApprovalsProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './ApprovalsProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/ApprovalsProvider/isActionsUpdate.ts: -------------------------------------------------------------------------------- 1 | import { Actions, ActionsEvent, ExtensionConnectionEvent } from '@core/types'; 2 | 3 | export const isActionsUpdate = ( 4 | ev: ExtensionConnectionEvent, 5 | ): ev is ExtensionConnectionEvent => 6 | ev.name === ActionsEvent.ACTION_UPDATED; 7 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/ApprovalsProvider/isApprovalRequest.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ApprovalEvent, 3 | ApprovalRequest, 4 | ExtensionConnectionEvent, 5 | } from '@core/types'; 6 | 7 | export function isApprovalRequest( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt?.name === ApprovalEvent.ApprovalRequested; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/BalancesProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './BalancesProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/BalancesProvider/isBalancesUpdatedEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BalanceServiceEvents, 3 | BalancesInfo, 4 | ExtensionConnectionEvent, 5 | } from '@core/types'; 6 | 7 | export function isBalancesUpdatedEvent( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === BalanceServiceEvents.UPDATED; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/ContactsProvider/contactsEventFilters.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ContactsState, 3 | ContactsEvents, 4 | ExtensionConnectionEvent, 5 | } from '@core/types'; 6 | 7 | export function contactsUpdatedEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === ContactsEvents.CONTACTS_UPDATED; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/ContactsProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './ContactsProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/CurrenciesProvider/currencyRatesEventFilters.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CurrencyServiceEvents, 3 | CurrencyExchangeRatesState, 4 | ExtensionConnectionEvent, 5 | } from '@core/types'; 6 | 7 | export function currencyRatesUpdatedEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === CurrencyServiceEvents.RatesUpdated; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/CurrenciesProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './CurrenciesProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/DefiProvider/defiEventFilters.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DefiPortfolioUpdatedEvent, 3 | DefiServiceEvents, 4 | ExtensionConnectionEvent, 5 | } from '@core/types'; 6 | 7 | export function defiPortfolioUpdatedEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === DefiServiceEvents.PortfolioUpdated; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/DefiProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './DefiProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/FeatureFlagsProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './FeatureFlagsProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/FeatureFlagsProvider/isFeatureFlagsUpdatedEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | FeatureFlagEvents, 4 | FeatureGates, 5 | } from '@core/types'; 6 | 7 | export function isFeatureFlagsUpdatedEvent( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent> { 10 | return evt.name === FeatureFlagEvents.FEATURE_FLAG_UPDATED; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/LedgerProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './LedgerProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/LedgerProvider/listeners.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | LedgerDeviceRequestData, 4 | LedgerEvent, 5 | } from '@core/types'; 6 | 7 | export function ledgerDiscoverTransportsEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent<{ name: LedgerEvent.DISCOVER_TRANSPORTS }> { 10 | return evt.name === LedgerEvent.DISCOVER_TRANSPORTS; 11 | } 12 | 13 | export function isLedgerDeviceRequestEvent( 14 | evt: ExtensionConnectionEvent, 15 | ): evt is ExtensionConnectionEvent { 16 | return evt.name === LedgerEvent.TRANSPORT_REQUEST; 17 | } 18 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/NetworkFeeProvider/gaslessChallangeUpdateListener.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | GaslessEvents, 4 | GaslessState, 5 | } from '@core/types'; 6 | 7 | export function gaslessChallangeUpdateEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === GaslessEvents.STATE_UPDATE; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/NetworkFeeProvider/gaslessSendMessageListener.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | GaslessEvents, 4 | GaslessMessage, 5 | } from '@core/types'; 6 | 7 | export function gaslessSendOffscreenMessageEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ) { 10 | return evt.name === GaslessEvents.SEND_OFFSCREEN_MESSAGE; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/NetworkFeeProvider/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NetworkFeeProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/NetworkProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './NetworkProvider'; 2 | export * from './networkChanges'; 3 | export * from './networksUpdatedEventListener'; 4 | export * from './isNetworkUpdatedEvent'; 5 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/NetworkProvider/isNetworkUpdatedEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | NetworkEvents, 4 | NetworkWithCaipId, 5 | } from '@core/types'; 6 | 7 | export function isNetworkUpdatedEvent( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === NetworkEvents.NETWORK_UPDATE_EVENT; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/NetworkProvider/networkChanges.ts: -------------------------------------------------------------------------------- 1 | import { Signal, ValueCache } from 'micro-signals'; 2 | 3 | const networkChanged = new Signal(); 4 | const networkChanges = networkChanged.cache( 5 | new ValueCache(), 6 | ); 7 | 8 | // Dispatch immediately so there is at least one item in the signal stream. 9 | networkChanged.dispatch(''); 10 | 11 | export { networkChanged, networkChanges }; 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/NetworkProvider/networksUpdatedEventListener.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | NetworkEvents, 4 | NetworkWithCaipId, 5 | } from '@core/types'; 6 | 7 | export function networksUpdatedEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent<{ 10 | networks: NetworkWithCaipId[]; 11 | activeNetwork?: NetworkWithCaipId; 12 | favoriteNetworks: number[]; 13 | customNetworks: Record; 14 | }> { 15 | return evt.name === NetworkEvents.NETWORKS_UPDATED_EVENT; 16 | } 17 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/OnboardingProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './OnboardingProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/OnboardingProvider/listeners.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | OnboardingEvents, 4 | OnboardingState, 5 | } from '@core/types'; 6 | 7 | export function onboardingUpdatedEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === OnboardingEvents.ONBOARDING_UPDATED_EVENT; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/PermissionsProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './PermissionsProvider'; 2 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/PermissionsProvider/permissionsEventFilters.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | PermissionEvents, 4 | Permissions, 5 | } from '@core/types'; 6 | 7 | export function permissionsUpdatedEventListener( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === PermissionEvents.PERMISSIONS_STATE_UPDATE; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/SettingsProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './SettingsProvider'; 2 | export * from './models'; 3 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/SettingsProvider/isSettingsUpdatedEvent.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ExtensionConnectionEvent, 3 | SettingsEvents, 4 | SettingsState, 5 | } from '@core/types'; 6 | 7 | export function isSettingsUpdatedEvent( 8 | evt: ExtensionConnectionEvent, 9 | ): evt is ExtensionConnectionEvent { 10 | return evt.name === SettingsEvents.SETTINGS_UPDATED; 11 | } 12 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/SettingsProvider/models.ts: -------------------------------------------------------------------------------- 1 | export enum SettingsPages { 2 | ADD_CONTACT = 'ADD_CONTACT', 3 | CHANGE_PASSWORD = 'CHANGE_PASSWORD', 4 | CONTACT_LIST = 'CONTACT_LIST', 5 | CONTACT_PROFILE = 'CONTACT_PROFILE', 6 | CURRENCIES = 'CURRENCIES', 7 | MAIN_PAGE = 'MAIN_PAGE', 8 | RECOVERY_PHRASE = 'RECOVERY_PHRASE', 9 | SECURITY_AND_PRIVACY = 'SECURITY_AND_PRIVACY', 10 | CONNECTED_SITES = 'CONNECTED_SITES', 11 | LEDGER = 'LEDGER', 12 | LEGAL = 'LEGAL', 13 | ADVANCED = 'ADVANCED', 14 | LANGUAGE = 'LANGUAGE', 15 | FEEDBACK = 'FEEDBACK', 16 | EXPORT_RECOVERY_PHRASE = 'EXPORT_RECOVERY_PHRASE', 17 | RECOVERY_METHODS = 'RECOVERY_METHODS', 18 | NOTIFICATIONS = 'NOTIFICATIONS', 19 | } 20 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/SwapProvider/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './SwapProvider'; 2 | export * from './models'; 3 | export * from './constants'; 4 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/WalletConnectContextProvider/index.ts: -------------------------------------------------------------------------------- 1 | export * from './WalletConnectContextProvider'; 2 | export * from './models'; 3 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/isSubscriptionsChangedEvent.ts: -------------------------------------------------------------------------------- 1 | import { ExtensionConnectionEvent, SubscriptionEvents } from '@core/types'; 2 | 3 | export function isSubscriptionsChangedEvent( 4 | evt: ExtensionConnectionEvent, 5 | ): evt is ExtensionConnectionEvent { 6 | return evt.name === SubscriptionEvents.SUBSCRIPTIONS_CHANGED_EVENT; 7 | } 8 | -------------------------------------------------------------------------------- /packages/ui/src/contexts/utils/getLedgerTransport.ts: -------------------------------------------------------------------------------- 1 | import TransportWebUSB from '@ledgerhq/hw-transport-webusb'; 2 | import { resolve } from '@core/common'; 3 | import Transport from '@ledgerhq/hw-transport'; 4 | import { Monitoring } from '@core/common'; 5 | 6 | export async function getLedgerTransport(): Promise { 7 | const [usbTransport, error] = await resolve(TransportWebUSB.openConnected()); 8 | 9 | if (usbTransport) { 10 | return usbTransport; 11 | } 12 | 13 | if (error) { 14 | Monitoring.sentryCaptureException( 15 | error as Error, 16 | Monitoring.SentryExceptionTypes.LEDGER, 17 | ); 18 | console.error('Unable to open ledger transport', error); 19 | } 20 | 21 | return null; 22 | } 23 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useAppTypeFromParams.ts: -------------------------------------------------------------------------------- 1 | import { LedgerAppType } from '../contexts/LedgerProvider'; 2 | import { useMemo } from 'react'; 3 | import { useLocation } from 'react-router-dom'; 4 | import xss from 'xss'; 5 | 6 | export const useAppTypeFromParams = (): LedgerAppType => { 7 | const { search } = useLocation(); 8 | 9 | return useMemo(() => { 10 | const { app } = (Object as any).fromEntries( 11 | (new URLSearchParams(search) as any).entries(), 12 | ); 13 | return xss(app) as LedgerAppType; 14 | }, [search]); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useBalanceTotalInCurrency.ts: -------------------------------------------------------------------------------- 1 | import { useBalancesContext } from '../contexts'; 2 | import { Account } from '@core/types'; 3 | import { useMemo } from 'react'; 4 | 5 | export function useBalanceTotalInCurrency(account?: Account) { 6 | const { getTotalBalance } = useBalancesContext(); 7 | 8 | return useMemo(() => { 9 | if (!account?.addressC) { 10 | return null; 11 | } 12 | 13 | return getTotalBalance(account.addressC); 14 | }, [account?.addressC, getTotalBalance]); 15 | } 16 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useCoinGeckoId.ts: -------------------------------------------------------------------------------- 1 | import { useTokenInfoContext } from '@avalabs/core-bridge-sdk'; 2 | 3 | // This is a copy from https://github.com/ava-labs/core-web-properties/blob/develop/packages/web/src/hooks/bridge/useCoingeckoId.ts 4 | 5 | const KNOWN_IDS = { 6 | BTC: 'bitcoin', 7 | AVAX: 'avalanche-2', 8 | ETH: 'ethereum', 9 | }; 10 | 11 | export const useCoinGeckoId = (tokenSymbol?: string): string | undefined => { 12 | const tokenInfoData = useTokenInfoContext(); 13 | 14 | return ( 15 | tokenSymbol && 16 | (KNOWN_IDS[tokenSymbol] || tokenInfoData?.[tokenSymbol]?.coingeckoId) 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useContactIdFromParams.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { useLocation } from 'react-router-dom'; 3 | import xss from 'xss'; 4 | 5 | export const useContactIdFromParams = () => { 6 | const { search } = useLocation(); 7 | 8 | return useMemo(() => { 9 | const { contactId } = (Object as any).fromEntries( 10 | (new URLSearchParams(search) as any).entries(), 11 | ); 12 | 13 | return { 14 | contactId: xss(contactId), 15 | }; 16 | }, [search]); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useFidoErrorMessage.ts: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next'; 2 | 3 | import { AuthErrorCode } from '@core/types'; 4 | 5 | export const useFidoErrorMessage = (code?: AuthErrorCode): string => { 6 | const { t } = useTranslation(); 7 | 8 | if (code === AuthErrorCode.FidoChallengeNotApproved) { 9 | return t('Action was not approved. Please try again.'); 10 | } 11 | 12 | if (code === AuthErrorCode.FidoChallengeFailed) { 13 | return t( 14 | 'The operation either timed out or was not allowed. Please try again.', 15 | ); 16 | } 17 | 18 | if (code === AuthErrorCode.UnknownError) { 19 | return t('An unexpected error occurred. Please try again.'); 20 | } 21 | 22 | return ''; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useGetAvaxBalance.ts: -------------------------------------------------------------------------------- 1 | import { GetNativeBalanceHandler } from '@core/service-worker'; 2 | import { ExtensionRequest } from '@core/types'; 3 | import { useConnectionContext } from '../contexts'; 4 | 5 | export function useGetAvaxBalance() { 6 | const { request } = useConnectionContext(); 7 | async function getAvaxBalance(address: string) { 8 | const result = await request({ 9 | method: ExtensionRequest.BALANCE_NATIVE_GET, 10 | params: [address, 'eip155:43114'], 11 | }); 12 | return result; 13 | } 14 | 15 | return { 16 | getAvaxBalance, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useGetRequestId.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { useLocation } from 'react-router-dom'; 3 | 4 | /** 5 | * This is used to get the id of a transaction or message that 6 | * has been put into localstorage and to be used across multiple 7 | * contexts. We grab the query param and use that to get the item out of storage. 8 | * 9 | * @returns id from the query param 10 | */ 11 | export function useGetRequestId() { 12 | const location = useLocation(); 13 | 14 | return useMemo(() => { 15 | const searchParams = new URLSearchParams(location.search ?? ''); 16 | return searchParams.get('actionId') ?? ''; 17 | }, [location.search]); 18 | } 19 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useGetSolBalance.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from 'react'; 2 | import { SolanaCaip2ChainId } from '@avalabs/core-chains-sdk'; 3 | 4 | import { ExtensionRequest } from '@core/types'; 5 | import { GetNativeBalanceHandler } from '@core/service-worker'; 6 | import { useConnectionContext } from '../contexts'; 7 | 8 | export function useGetSolBalance() { 9 | const { request } = useConnectionContext(); 10 | 11 | const getSolBalance = useCallback( 12 | async (address: string) => 13 | request({ 14 | method: ExtensionRequest.BALANCE_NATIVE_GET, 15 | params: [address, SolanaCaip2ChainId.MAINNET], 16 | }), 17 | [request], 18 | ); 19 | 20 | return { 21 | getSolBalance, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useGoBack.ts: -------------------------------------------------------------------------------- 1 | import { useHistory } from 'react-router-dom'; 2 | 3 | export function useGoBack(routeToGoBack = '/home') { 4 | const history = useHistory(); 5 | 6 | return () => { 7 | if (history.length <= 2) { 8 | history.replace(routeToGoBack); 9 | return; 10 | } 11 | 12 | history.goBack(); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useInterval.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | /** 4 | * Simple way to have trigger something based on a time interval. 5 | * @param intervalDurationMs duration of interval in milliseconds 6 | * @returns the most recent time the interval was triggered. 7 | */ 8 | export function useInterval(intervalDurationMs: number) { 9 | const [intervalTime, setIntervalTime] = useState(Date.now()); 10 | 11 | useEffect(() => { 12 | let mounted = true; 13 | const intervalId = setInterval(() => { 14 | if (mounted) setIntervalTime(Date.now()); 15 | }, intervalDurationMs); 16 | 17 | return () => { 18 | mounted = false; 19 | clearInterval(intervalId); 20 | }; 21 | }, [intervalDurationMs]); 22 | 23 | return intervalTime; 24 | } 25 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsMainnet.ts: -------------------------------------------------------------------------------- 1 | import { useNetworkContext } from '../contexts'; 2 | 3 | export const useIsMainnet = () => { 4 | const { network } = useNetworkContext(); 5 | return !network?.isTestnet; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsSolanaEnabled.ts: -------------------------------------------------------------------------------- 1 | import { FeatureGates } from '@core/types'; 2 | import { useFeatureFlagContext } from '../contexts'; 3 | 4 | export const useIsSolanaEnabled = () => { 5 | const { isFlagEnabled } = useFeatureFlagContext(); 6 | 7 | return isFlagEnabled(FeatureGates.SOLANA_SUPPORT); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsSpecificContextContainer.ts: -------------------------------------------------------------------------------- 1 | import type { ContextContainer } from '@core/types'; 2 | import { useMemo } from 'react'; 3 | 4 | export function useIsSpecificContextContainer(context: ContextContainer) { 5 | return useMemo(() => { 6 | return window.location.pathname.includes(context); 7 | }, [context]); 8 | } 9 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsUsingFireblocksAccount.ts: -------------------------------------------------------------------------------- 1 | import { AccountType } from '@core/types'; 2 | import { useAccountsContext } from '../contexts'; 3 | 4 | export const useIsUsingFireblocksAccount = () => { 5 | const { 6 | accounts: { active: activeAccount }, 7 | } = useAccountsContext(); 8 | 9 | return activeAccount?.type === AccountType.FIREBLOCKS; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsUsingKeystoneWallet.ts: -------------------------------------------------------------------------------- 1 | import { useAccountsContext } from '../contexts'; 2 | import { useWalletContext } from '../contexts'; 3 | import { AccountType, SecretType } from '@core/types'; 4 | 5 | export const useIsUsingKeystoneWallet = () => { 6 | const { walletDetails } = useWalletContext(); 7 | const { 8 | accounts: { active: activeAccount }, 9 | } = useAccountsContext(); 10 | 11 | return ( 12 | walletDetails?.type === SecretType.Keystone && 13 | activeAccount?.type === AccountType.PRIMARY 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsUsingLedgerWallet.ts: -------------------------------------------------------------------------------- 1 | import { AccountType } from '@core/types'; 2 | import { useAccountsContext } from '../contexts'; 3 | import { useWalletContext } from '../contexts'; 4 | 5 | export const useIsUsingLedgerWallet = () => { 6 | const { isLedgerWallet } = useWalletContext(); 7 | const { 8 | accounts: { active: activeAccount }, 9 | } = useAccountsContext(); 10 | 11 | return isLedgerWallet && activeAccount?.type === AccountType.PRIMARY; 12 | }; 13 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsUsingSeedlessAccount.ts: -------------------------------------------------------------------------------- 1 | import { AccountType, SecretType } from '@core/types'; 2 | import { useAccountsContext } from '../contexts'; 3 | import { useWalletContext } from '../contexts'; 4 | 5 | export const useIsUsingSeedlessAccount = () => { 6 | const { walletDetails } = useWalletContext(); 7 | const { 8 | accounts: { active: activeAccount }, 9 | } = useAccountsContext(); 10 | 11 | return ( 12 | walletDetails?.type === SecretType.Seedless && 13 | activeAccount?.type === AccountType.PRIMARY 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useIsUsingWalletConnectAccount.ts: -------------------------------------------------------------------------------- 1 | import { AccountType } from '@core/types'; 2 | import { useAccountsContext } from '../contexts'; 3 | 4 | export const useIsUsingWalletConnectAccount = () => { 5 | const { 6 | accounts: { active: activeAccount }, 7 | } = useAccountsContext(); 8 | 9 | return activeAccount?.type === AccountType.WALLET_CONNECT; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useKeyboardShortcuts.ts: -------------------------------------------------------------------------------- 1 | import { KeyboardEventHandler, useCallback } from 'react'; 2 | 3 | type Callback = () => void; 4 | type KeyNames = 'Enter' | 'Escape'; 5 | type KeyboardShortcuts = Partial>; 6 | 7 | export const useKeyboardShortcuts = (shortcuts: KeyboardShortcuts) => { 8 | const onKeyDown: KeyboardEventHandler = useCallback( 9 | async (event) => { 10 | const callback = shortcuts[event.key]; 11 | 12 | if (typeof callback === 'function') { 13 | event.preventDefault(); 14 | await callback(); 15 | } 16 | }, 17 | [shortcuts], 18 | ); 19 | 20 | return { 21 | onKeyDown, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useLiveBalance.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { useBalancesContext } from '../contexts'; 3 | import { TokenType } from '@avalabs/vm-module-types'; 4 | 5 | export const useLiveBalance = (tokenTypes: TokenType[]) => { 6 | const { registerSubscriber, unregisterSubscriber } = useBalancesContext(); 7 | 8 | useEffect(() => { 9 | registerSubscriber(tokenTypes); 10 | 11 | return () => { 12 | unregisterSubscriber(tokenTypes); 13 | }; 14 | }, [registerSubscriber, unregisterSubscriber, tokenTypes]); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useLocalStorage.ts: -------------------------------------------------------------------------------- 1 | import { storage } from 'webextension-polyfill'; 2 | 3 | export const useLocalStorage = () => { 4 | return { 5 | async get(key: string) { 6 | const stored = await storage.local.get(key); 7 | 8 | return stored[key]; 9 | }, 10 | async set(key: string, value: any) { 11 | return storage.local.set({ [key]: value }); 12 | }, 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useOnline.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export function useOnline() { 4 | const [isOnline, setIsOnline] = useState(window.navigator.onLine); 5 | 6 | useEffect(() => { 7 | const onConnectionChange = (event) => { 8 | if (event.type === 'online') { 9 | setIsOnline(true); 10 | return; 11 | } 12 | setIsOnline(false); 13 | }; 14 | 15 | window.addEventListener('online', onConnectionChange); 16 | 17 | window.addEventListener('offline', onConnectionChange); 18 | return () => { 19 | window.removeEventListener('online', () => onConnectionChange); 20 | window.removeEventListener('offline', () => onConnectionChange); 21 | }; 22 | }, []); 23 | 24 | return { isOnline }; 25 | } 26 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useQueryParams.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { useLocation } from 'react-router-dom'; 3 | 4 | export const useQueryParams = () => { 5 | const { search } = useLocation(); 6 | 7 | return useMemo(() => new URLSearchParams(search), [search]); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useSendAnalyticsData.ts: -------------------------------------------------------------------------------- 1 | import { useAnalyticsContext } from '../contexts'; 2 | import { useCallback } from 'react'; 3 | 4 | export function useSendAnalyticsData() { 5 | const { capture } = useAnalyticsContext(); 6 | const sendTokenSelectedAnalytics = useCallback( 7 | (functionality: string) => { 8 | capture(`${functionality}_TokenSelected`); 9 | }, 10 | [capture], 11 | ); 12 | const sendAmountEnteredAnalytics = useCallback( 13 | (functionality: string) => { 14 | capture(`${functionality}_AmountEntered`); 15 | }, 16 | [capture], 17 | ); 18 | 19 | return { 20 | sendTokenSelectedAnalytics, 21 | sendAmountEnteredAnalytics, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useTabFromParams.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | import { useLocation } from 'react-router-dom'; 3 | import xss from 'xss'; 4 | 5 | export const useTabFromParams = () => { 6 | const { search } = useLocation(); 7 | 8 | return useMemo(() => { 9 | const { activeTab } = (Object as any).fromEntries( 10 | (new URLSearchParams(search) as any).entries(), 11 | ); 12 | 13 | return { 14 | activeTab: xss(activeTab), 15 | }; 16 | }, [search]); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useTotpErrorMessage.ts: -------------------------------------------------------------------------------- 1 | import { AuthErrorCode } from '@core/types'; 2 | import { useTranslation } from 'react-i18next'; 3 | 4 | export const useTotpErrorMessage = (code?: AuthErrorCode): string => { 5 | const { t } = useTranslation(); 6 | 7 | if (code === AuthErrorCode.InvalidTotpCode) { 8 | return t('Invalid code. Please try again.'); 9 | } 10 | 11 | if (code === AuthErrorCode.TotpVerificationError) { 12 | return t('We were not able to verify this code. Please try again.'); 13 | } 14 | 15 | return ''; 16 | }; 17 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useWalletTotalBalance.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | 3 | import { 4 | WalletTotalBalanceState, 5 | useWalletTotalBalanceContext, 6 | } from '../contexts/WalletTotalBalanceProvider'; 7 | 8 | export const useWalletTotalBalance = (walletId?: string) => { 9 | const { walletBalances } = useWalletTotalBalanceContext(); 10 | 11 | return useMemo( 12 | (): WalletTotalBalanceState => 13 | (walletId && walletBalances[walletId]) || { 14 | isLoading: false, 15 | hasErrorOccurred: false, 16 | }, 17 | [walletBalances, walletId], 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/ui/src/hooks/useWillSwitchToPrimaryAccount.ts: -------------------------------------------------------------------------------- 1 | import { AccountType } from '@core/types'; 2 | import { useAccountsContext } from '../contexts'; 3 | import { isProductionBuild } from '@core/common'; 4 | 5 | export function useWillSwitchToPrimaryAccount( 6 | isSwitchingToTestnetMode: boolean, 7 | ) { 8 | const { 9 | accounts: { active: activeAccount }, 10 | } = useAccountsContext(); 11 | 12 | const isFireblocksAccount = activeAccount?.type === AccountType.FIREBLOCKS; 13 | 14 | return Boolean( 15 | isProductionBuild() && isSwitchingToTestnetMode && isFireblocksAccount, 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /packages/ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './contexts'; 2 | export * from './hooks'; 3 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@core/tsconfig/tsconfig.base.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "~/*": ["../service-worker/src/*"], 6 | "@shared/*": ["../../src/*"] 7 | }, 8 | "jsx": "react-jsx" 9 | }, 10 | "exclude": ["**/node_modules/*"], 11 | "include": ["./src", "../types/*.d.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /src/tests/MockTextEncoder.ts: -------------------------------------------------------------------------------- 1 | import { TextEncoder } from 'util'; 2 | 3 | // need to wrap the mock coming from node-utils since return type of the encode method is not type correct 4 | export class MockTextEncoder { 5 | encoder: TextEncoder; 6 | readonly encoding: string; 7 | constructor() { 8 | this.encoder = new TextEncoder(); 9 | this.encoding = this.encoder.encoding; 10 | } 11 | 12 | encode(input?: string): Uint8Array { 13 | return Uint8Array.from(this.encoder.encode(input)); 14 | } 15 | 16 | encodeInto(src: string, dest: Uint8Array) { 17 | return this.encoder.encodeInto(src, dest); 18 | } 19 | } 20 | --------------------------------------------------------------------------------