├── .env.d.ts ├── .env.example ├── .eslintignore ├── .eslintrc.js ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── actions │ ├── chromeTestsSetup │ │ └── action.yml │ ├── firefoxTestsSetup │ │ └── action.yml │ └── testsSetup │ │ └── action.yml ├── hero.png └── workflows │ ├── build.yml │ ├── publish-internal.yml │ ├── publish-prod-chrome.yml │ ├── publish-prod-edge.yml │ ├── publish-prod-firefox.yml │ └── rebase.yml ├── .gitignore ├── .husky └── pre-commit ├── .nvmrc ├── .prettierignore ├── .prettierrc.js ├── .yarnrc ├── CHANGELOG.md ├── DepShield.js ├── LICENSE ├── README.md ├── README_FIREFOX.md ├── audit-ci.jsonc ├── crowdin.yml ├── e2e ├── fetchResponses.ts ├── helpers.ts ├── mockFetch.ts ├── mocks │ ├── mock_swap_quotes_urls.json │ └── swap_quotes │ │ ├── 0x00eee74c6fa73c08ecaccb23d69352a4ecfb03c0fc7e2258ace1d63b0264abc2.json │ │ ├── 0x038dce7884e70b272cd1e2451c7ac6c7acead26c6fbd4593ac6840211a966072.json │ │ ├── 0x1fff3bc1f1da3704a60b836efa10528143a50bb300b9461457d46c445f5f439d.json │ │ ├── 0x2522bc7da8c360a103d31c1941b2874c56de2ef59667a8347ca9dd9412b00323.json │ │ ├── 0x2d17452c5f161d4c653a5f82922341249fe74c24c68b2598964074187873f2ed.json │ │ ├── 0x2eb23074686a20f6e0cb064d999214d6e5a8da3995979e418f485bb55744c15d.json │ │ ├── 0x32c0b9ce96014842fb892fc278855ca510fa9d9de64fc2fe3e9f3ef2d704357d.json │ │ ├── 0x379416b0e8e9f9e36b45eec57b1978238f5af1496206e9a8ce28dddfe3945ed7.json │ │ ├── 0x380e8f14b89b3978200ba3ebdf88ac6174b8a3b404b29365546e983e9ab1e587.json │ │ ├── 0x38b342e1dabe2c1fc1fe8a752034c591a68e8a669e6742c7967770a95ec8ef76.json │ │ ├── 0x3e2cb30acbc75f04a7b16cc82c8c248cb38fd6f8bc6dc3cfd8cff8802f3b9ff5.json │ │ ├── 0x47340cf37ec568d85c017c8c9cacfb330a6aefd1515158e75066ad213bf7cc1f.json │ │ ├── 0x4bbc11ada78a41c1d6988ddb4c961616ffda14648a6999609b05dfa8e0f23040.json │ │ ├── 0x4bfecb6351d987a221ca103e06fbabc34c4a6fea57281318cc064f299f36413c.json │ │ ├── 0x51408ac431ed2f22c59d356ad0d8ba3bb68cb1e090d5d0aef8ae9b9a0792a8ca.json │ │ ├── 0x5b069bb5fcbc7762c47959f7b44a6b9ef0bec6284bdc7e4233ae746bcc596368.json │ │ ├── 0x5bc1b94c5044bd672aec84cf0bb749a11c10eb73c2b2a393932fe283b46db182.json │ │ ├── 0x66297c56338a4369baea388ffc78f69380944266107ebf957b7b65eb98fe036a.json │ │ ├── 0x741198ed8cce7db26e5189437e915752765779b3800aa8b4492c5895f34e7204.json │ │ ├── 0x75c48fb2f0c937df972f466d7ee5e66fa2475b9fa2a10a0a17e3d9719519ee87.json │ │ ├── 0x7f2733a251e1a520c9811b6358e486d626d77e2a94319438381588727f374885.json │ │ ├── 0x80859a5a4665bc984c08fbc08db3743c1005992a1d946a7e393ecaecdf54b634.json │ │ ├── 0x81f456006fc8b4d42d0d8e99d45c951a8317dc2b29943b3fd6e913c722b9b178.json │ │ ├── 0x82e5be6ece179ad176c3150fef03875b41e3598031a1cf46c09b0b4934d08523.json │ │ ├── 0x84107854688a76e0f03b495ef1a357372bfc463994ee60fb158f1283c22cf77d.json │ │ ├── 0x8de7fe00b0e00a66f07a660733aa2d931fb516d24ee2fb2a31d5ea109f17518a.json │ │ ├── 0x8e251beba0b431141909ce01265f2219557f895f813031ca44786efed13d3bd5.json │ │ ├── 0x90c3bea3971a8eceec9f69672f8792f62f780eff333bc308ce72544e61141289.json │ │ ├── 0x939bdc6a9c8d3d009be3e4daa82c2a06a0db30353cd50d2a607c53cbba045001.json │ │ ├── 0x9a0f9a2a14982214eb247a285bb83ca5028efba339509b4fe942f7189e0afb3c.json │ │ ├── 0xa7d8182320bc29f6e1843019fe70885a8f485991693197745ae20023a99b0adb.json │ │ ├── 0xa8851b608dc6212889006842c206dda15a1e718768e1d16afb87a69a2e04753c.json │ │ ├── 0xaa0ad349da2ff82c83d4d9c770898312e46c68a34c0c0bc5c17732944b249bbf.json │ │ ├── 0xaf758611b699ddb0772bfb18d394fda79babed75e02c6ec68787f8ec8c4b6a5e.json │ │ ├── 0xb8d81e75e8537dd8b96f3e9a79968ad795560aa0cba40b4297e1c164b6e3106a.json │ │ ├── 0xc26272c5bf19cd649972abbac018d89c6d8a5c07d70719c464f63dfadbaa9ac7.json │ │ ├── 0xd1f1a419f92e46057710f9f0c9617ef2b6a391229f1a73de98e4f4ef829b7bc7.json │ │ ├── 0xd29876457b7fd7b56832bfd10a0af3ec343beb1d49a5213cbd69eab8cc9f7653.json │ │ ├── 0xd340e47b8638803ad11ee4a801d39e1553126acdec24f8bd8b8fca32eeef4917.json │ │ ├── 0xd37cfab3f9456439dc8c0cdfee67eb993e67ac7b14ddd6be49a961d1955c28c1.json │ │ ├── 0xd93b0e4edf8ca955c914cc7ed4d9176834f8e7b9324cf26b724cc0f7345dbd39.json │ │ ├── 0xdbc0f49ff7efb45dca12f62922f205e1e3324f0a693d40f6d0433ea681df9436.json │ │ ├── 0xe1a1cb8f0c4bf8028c0330d096feb5e727d4c91a6a12cf2f6494cda55145e9df.json │ │ ├── 0xea83715b8b512e5444577de7a315e51d157d1bd2b53bb1398c5af0ca98f1ad7e.json │ │ ├── 0xebd75d0517e2e15e1b4ff167ad5c4f2c214e9e0f65224c2b8acd1c5d4902523f.json │ │ ├── 0xf67dfbc6441947ed8384222e3dd88dbcf7b4a37bceef60a2f78dfbf06d71a23e.json │ │ ├── 0xf6be4896f04adb2829a5edd8386ffb96d87c47a6beda5545d0b71edbfe204782.json │ │ ├── 0xf7ef0fb43f50e89350d18de1fb4d1f99c2320f2f82efe312a8583250ce632527.json │ │ ├── 0xf9fd9c875d226201534eb0afe98bc64b5aa76a30c04bdb629b8e5286b010d67d.json │ │ └── 0xfafa8443a4a3eabafe4a84a138a4762cc774ca5c6f734e4efcaefd73cdd364aa.json ├── numbers.ts ├── parallel │ ├── LedgerImportFlow.test.ts │ ├── TrezorImportFlow.test.ts │ ├── commandKFlow.test.ts │ ├── importWalletFlow.test.ts │ ├── importWalletFlowPkey.test.ts │ ├── newWalletFlow.test.ts │ ├── nftsFlow.test.ts │ ├── settingsFlows.test.ts │ ├── settingsPrivacyFlows.test.ts │ ├── shortcuts-home.test.ts │ ├── shortcuts-settings.test.ts │ ├── shortcuts-walletSwitcher.test.ts │ ├── vitest.config.ts │ └── watchWalletFlow.test.ts ├── serial │ ├── dappInteractions │ │ ├── 1_appInteractionsFlow.test.ts │ │ ├── 2_dappInteractionFlow.test.ts │ │ ├── 3_dappAccountsSwitcher.test.ts │ │ ├── 4_networksAndTestnetModeFlow.test.ts │ │ └── 5_maliciousDapp.test.ts │ ├── optimismTransactions │ │ └── 1_sendFlow.test.ts │ ├── send │ │ ├── 1_sendFlow.test.ts │ │ ├── 2_shortcuts-sendFlow.test.ts │ │ ├── 3_customNetworks.test.ts │ │ └── 4_nft-sendFlow.test.ts │ ├── swap │ │ ├── 1_swapFlow1.test.ts │ │ ├── 2_swapFlow2.test.ts │ │ └── 3_shortcuts-swapFlow.test.ts │ └── vitest.config.ts ├── tokenVariables.ts ├── vitest.config.ts └── walletVariables.ts ├── lavamoat ├── browserify │ ├── background │ │ ├── policy-override.json │ │ └── policy.json │ ├── index.worker.worker │ │ ├── policy-override.json │ │ └── policy.json │ ├── injectProvider │ │ ├── policy-override.json │ │ └── policy.json │ ├── inpage │ │ ├── policy-override.json │ │ └── policy.json │ └── popup │ │ ├── policy-override.json │ │ └── policy.json ├── build-lavamoat │ ├── policy-override.json │ └── policy.json └── build-webpack │ ├── policy-override.json │ └── policy.json ├── lint-staged.config.js ├── manifest ├── internal.json └── prod.json ├── package.json ├── patches ├── @metamask+browser-passworder+4.1.0.patch ├── copy-webpack-plugin+11.0.0.patch └── deep-object-diff+1.1.7.patch ├── scripts ├── bump.js ├── check-lockfile.sh ├── e2e-op-serial-tests.sh ├── e2e-parallel-tests.sh ├── e2e-serial-tests.sh ├── firefox-manifest.js ├── get-rpc-url.sh ├── lavamoat-browserify.js ├── networks.js ├── unit-tests.sh ├── update-manifest.js └── webpack.js ├── src ├── analytics │ ├── README.md │ ├── event.ts │ ├── flushQueuedEvents.ts │ ├── identify │ │ └── walletTypes.ts │ ├── index.ts │ ├── queueEvent.ts │ ├── screen.ts │ ├── userProperties.ts │ └── util.ts ├── assets.d.ts ├── core │ ├── firebase │ │ ├── fcm.ts │ │ └── remoteConfig.ts │ ├── graphql │ │ ├── README.md │ │ ├── __generated__ │ │ │ ├── ens.ts │ │ │ └── metadata.ts │ │ ├── codegen.config.js │ │ ├── config.js │ │ ├── index.ts │ │ ├── package.json │ │ ├── queries │ │ │ ├── ens.graphql │ │ │ └── metadata.graphql │ │ ├── utils │ │ │ ├── buildGetQueryParams.ts │ │ │ └── getFetchRequester.ts │ │ └── yarn.lock │ ├── keychain │ │ ├── HWSigner.ts │ │ ├── IKeychain.ts │ │ ├── KeychainManager.test.ts │ │ ├── KeychainManager.ts │ │ ├── README.md │ │ ├── RainbowSigner.ts │ │ ├── hdPath.ts │ │ ├── index.test.ts │ │ ├── index.ts │ │ ├── keychainTypes │ │ │ ├── hardwareWalletKeychain.ts │ │ │ ├── hdKeychain.ts │ │ │ ├── keyPairKeychain.ts │ │ │ └── readOnlyKeychain.ts │ │ ├── utils.test.ts │ │ └── utils.ts │ ├── languages │ │ └── index.ts │ ├── messengers │ │ ├── README.md │ │ ├── index.ts │ │ ├── initializeMessenger.ts │ │ └── internal │ │ │ ├── bridge.ts │ │ │ ├── createMessenger.ts │ │ │ ├── extension.ts │ │ │ ├── isValidReply.ts │ │ │ ├── isValidSend.ts │ │ │ ├── tab.ts │ │ │ └── window.ts │ ├── network │ │ ├── _template.ts │ │ ├── addys.ts │ │ ├── aha.ts │ │ ├── etherscan.ts │ │ ├── f2c.ts │ │ ├── index.ts │ │ ├── internal │ │ │ ├── createHttpClient.ts │ │ │ ├── createWebSocketClient.ts │ │ │ └── rainbowFetch.ts │ │ ├── meteorology.ts │ │ ├── nftAllowList.ts │ │ ├── nfts.ts │ │ ├── refractionAssetsWs.ts │ │ └── tokenSearch.ts │ ├── providers │ │ └── proxy.ts │ ├── raps │ │ ├── actions │ │ │ ├── claim.ts │ │ │ ├── claimBridge.ts │ │ │ ├── crosschainSwap.test.ts │ │ │ ├── crosschainSwap.ts │ │ │ ├── index.ts │ │ │ ├── swap.test.ts │ │ │ ├── swap.ts │ │ │ ├── unlock.test.ts │ │ │ └── unlock.ts │ │ ├── claimAndBridge.ts │ │ ├── common.ts │ │ ├── execute.ts │ │ ├── references.ts │ │ ├── unlockAndCrosschainSwap.test.ts │ │ ├── unlockAndCrosschainSwap.ts │ │ ├── unlockAndSwap.test.ts │ │ ├── unlockAndSwap.ts │ │ └── utils.ts │ ├── react-query │ │ ├── createQueryKey.ts │ │ ├── index.ts │ │ ├── queryClient.ts │ │ └── types.ts │ ├── references │ │ ├── assets.ts │ │ ├── autoLockTimer.ts │ │ ├── ethUnits.ts │ │ ├── index.ts │ │ ├── links.ts │ │ ├── rawImages.ts │ │ ├── shortcuts.ts │ │ ├── supportedCurrencies.ts │ │ ├── themes.ts │ │ └── txSpeed.ts │ ├── resources │ │ ├── README.md │ │ ├── _selectors │ │ │ ├── assets.ts │ │ │ ├── index.ts │ │ │ ├── nfts.ts │ │ │ └── transactions.ts │ │ ├── _template │ │ │ ├── _templateMutation.ts │ │ │ └── _templateQuery.ts │ │ ├── addys │ │ │ └── addysSummary.ts │ │ ├── approvals │ │ │ └── approvals.ts │ │ ├── assets │ │ │ ├── assetMetadata.ts │ │ │ ├── assets.ts │ │ │ ├── common.ts │ │ │ ├── customNetworkAssets.ts │ │ │ ├── externalToken.ts │ │ │ ├── index.ts │ │ │ ├── userAssets.ts │ │ │ ├── userAssetsByChain.ts │ │ │ └── userTestnetNativeAsset.ts │ │ ├── chains │ │ │ └── chainMetadata.ts │ │ ├── ens │ │ │ ├── ensRegistration.ts │ │ │ └── index.ts │ │ ├── f2c │ │ │ ├── index.ts │ │ │ ├── providers.ts │ │ │ ├── types.ts │ │ │ └── widgetUrl.ts │ │ ├── gas │ │ │ ├── estimateApprovalGasLimit.ts │ │ │ ├── estimateGasLimit.ts │ │ │ ├── estimateSwapGasLimit.ts │ │ │ ├── gasData.ts │ │ │ ├── index.ts │ │ │ ├── meteorology.ts │ │ │ ├── optimismL1SecurityFee.ts │ │ │ └── providerGas.ts │ │ ├── metadata │ │ │ ├── dapp.ts │ │ │ ├── ensAvatar.ts │ │ │ └── ensProfile.ts │ │ ├── networks │ │ │ ├── networks.ts │ │ │ └── queries.js │ │ ├── nfts │ │ │ ├── collections.ts │ │ │ ├── galleryNfts.ts │ │ │ ├── index.ts │ │ │ ├── nftsForCollection.ts │ │ │ └── useNft.ts │ │ ├── positions │ │ │ └── index.ts │ │ ├── search │ │ │ ├── index.ts │ │ │ ├── parseTokenSearch.ts │ │ │ ├── popularInRainbow.ts │ │ │ └── tokenSearch.ts │ │ └── transactions │ │ │ ├── consolidatedTransactions.ts │ │ │ ├── firstTransactionTimestampQuery.ts │ │ │ ├── index.ts │ │ │ ├── registryLookup.ts │ │ │ ├── transaction.ts │ │ │ └── transactions.ts │ ├── sentry │ │ └── index.ts │ ├── state │ │ ├── appConnectionWalletSwitcher │ │ │ └── appConnectionSwitcher.ts │ │ ├── appSessions │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── contacts │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── currentHomeSheet │ │ │ └── index.ts │ │ ├── currentSettings │ │ │ ├── analyticsDisabled.ts │ │ │ ├── autoLockTimer.ts │ │ │ ├── connectedToHardhat.ts │ │ │ ├── currentAddress.ts │ │ │ ├── currentChainId.ts │ │ │ ├── currentCurrency.ts │ │ │ ├── currentLanguage.ts │ │ │ ├── currentTheme.ts │ │ │ ├── defaultTxSpeed.ts │ │ │ ├── developerToolsEnabled.ts │ │ │ ├── featureFlags.ts │ │ │ ├── hideAssetBalances.ts │ │ │ ├── hideSmallBalances.ts │ │ │ ├── index.test.ts │ │ │ ├── index.ts │ │ │ ├── isDefaultWallet.ts │ │ │ ├── tabNavigation.ts │ │ │ └── testnetMode.ts │ │ ├── dappMetadata │ │ │ └── index.ts │ │ ├── degenMode │ │ │ └── index.ts │ │ ├── deviceId │ │ │ └── index.ts │ │ ├── dominantColor │ │ │ └── index.ts │ │ ├── error │ │ │ └── index.ts │ │ ├── favorites │ │ │ └── index.ts │ │ ├── gas │ │ │ └── index.ts │ │ ├── hiddenAssets │ │ │ └── hiddenAssets.ts │ │ ├── hiddenWallets │ │ │ └── index.ts │ │ ├── homePromptsQueue │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── internal │ │ │ ├── SubscriptionManager.ts │ │ │ ├── createQueryStore.ts │ │ │ ├── createRainbowStore.ts │ │ │ ├── createStore.ts │ │ │ ├── persistStorage.ts │ │ │ ├── signal.ts │ │ │ └── syncStores.ts │ │ ├── navRestoration │ │ │ └── index.ts │ │ ├── networks │ │ │ ├── __tests__ │ │ │ │ ├── data │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── rainbowChains.mock.ts │ │ │ │ │ ├── userChains.mock.ts │ │ │ │ │ └── userChainsOrder.mock.ts │ │ │ │ └── networkStore.test.ts │ │ │ ├── constants.ts │ │ │ ├── migration.ts │ │ │ ├── networks.ts │ │ │ ├── runNetworksMigrationIfNeeded.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── nfts │ │ │ └── index.ts │ │ ├── nonce │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── notificationWindow.ts │ │ ├── pinnedAssets │ │ │ └── index.ts │ │ ├── popupInstances │ │ │ └── index.ts │ │ ├── quickPromo │ │ │ └── index.ts │ │ ├── rainbowChainAssets │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── rainbowChains │ │ │ └── index.ts │ │ ├── requests │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── savedEnsNames │ │ │ └── index.ts │ │ ├── selectedNft │ │ │ └── index.ts │ │ ├── selectedToken │ │ │ └── index.ts │ │ ├── selectedTransaction │ │ │ └── index.ts │ │ ├── sound │ │ │ └── index.ts │ │ ├── staleBalances │ │ │ ├── index.test.ts │ │ │ └── index.ts │ │ ├── swapAssetsToRefresh │ │ │ └── index.ts │ │ ├── transactions │ │ │ ├── customNetworkTransactions │ │ │ │ └── index.ts │ │ │ └── pendingTransactions │ │ │ │ └── index.ts │ │ ├── userChains │ │ │ └── index.ts │ │ ├── walletAvatar │ │ │ └── index.ts │ │ ├── walletBackups │ │ │ └── index.ts │ │ ├── walletNames │ │ │ └── index.ts │ │ └── walletOrder │ │ │ └── index.ts │ ├── storage │ │ ├── index.ts │ │ └── localStorageRecycler.ts │ ├── telemetry │ │ └── index.ts │ ├── transports │ │ ├── README.md │ │ ├── index.ts │ │ ├── internal │ │ │ └── createTransport.ts │ │ └── providerRequestTransport.ts │ ├── types │ │ ├── assets.ts │ │ ├── chains.ts │ │ ├── gas.ts │ │ ├── keychainTypes.ts │ │ ├── nfts.ts │ │ ├── refraction.ts │ │ ├── rpcMethods.ts │ │ ├── search.ts │ │ ├── settings.ts │ │ ├── transactions.ts │ │ ├── walletActions.ts │ │ └── walletTypes.ts │ ├── utils │ │ ├── __test__ │ │ │ └── numbers.test.ts │ │ ├── address.ts │ │ ├── assets.test.ts │ │ ├── assets.ts │ │ ├── chains.ts │ │ ├── colors.ts │ │ ├── connectedApps.ts │ │ ├── copy.ts │ │ ├── dates.ts │ │ ├── defaults.ts │ │ ├── deserializeBigNumbers.ts │ │ ├── detectScriptType.ts │ │ ├── dimensions.ts │ │ ├── draggable.ts │ │ ├── ethereum.test.ts │ │ ├── ethereum.ts │ │ ├── faucets.ts │ │ ├── formatDate.ts │ │ ├── formatNumber.ts │ │ ├── gas.ts │ │ ├── hex.ts │ │ ├── localJson.ts │ │ ├── locales.ts │ │ ├── lockdown.ts │ │ ├── methodRegistry.ts │ │ ├── nfts.ts │ │ ├── numbers.ts │ │ ├── persistOptions.ts │ │ ├── react.ts │ │ ├── settings.ts │ │ ├── signMessages.tsx │ │ ├── strings.ts │ │ ├── swaps.ts │ │ ├── tabs.ts │ │ ├── time.ts │ │ ├── transactions.ts │ │ ├── types.ts │ │ └── userChains.ts │ └── wagmi │ │ ├── clientRpc.ts │ │ ├── clientToProvider.ts │ │ └── index.ts ├── design-system │ ├── components │ │ ├── Accordion │ │ │ ├── Accordion.tsx │ │ │ └── accordion.css.ts │ │ ├── Alert │ │ │ └── Alert.tsx │ │ ├── AnimatedRoute │ │ │ ├── AnimatedRoute.css.ts │ │ │ └── AnimatedRoute.tsx │ │ ├── AnimatedText │ │ │ ├── AnimatedText.tsx │ │ │ └── AnimatedTextRows.tsx │ │ ├── Bleed │ │ │ ├── Bleed.docs.tsx │ │ │ ├── Bleed.examples.tsx │ │ │ └── Bleed.tsx │ │ ├── BottomSheet │ │ │ └── BottomSheet.tsx │ │ ├── Box │ │ │ ├── AccentColorProvider.docs.tsx │ │ │ ├── Box.docs.tsx │ │ │ ├── Box.examples.tsx │ │ │ ├── Box.tsx │ │ │ ├── ColorContext.tsx │ │ │ └── ThemeProvider.docs.tsx │ │ ├── Button │ │ │ ├── Button.css.ts │ │ │ ├── Button.docs.tsx │ │ │ ├── Button.examples.tsx │ │ │ ├── Button.tsx │ │ │ ├── ButtonOverflow.tsx │ │ │ ├── ButtonWrapper.css.ts │ │ │ └── ButtonWrapper.tsx │ │ ├── ButtonSymbol │ │ │ ├── ButtonSymbol.css.ts │ │ │ ├── ButtonSymbol.docs.tsx │ │ │ ├── ButtonSymbol.examples.tsx │ │ │ └── ButtonSymbol.tsx │ │ ├── Columns │ │ │ ├── Columns.css.ts │ │ │ ├── Columns.docs.tsx │ │ │ ├── Columns.examples.tsx │ │ │ └── Columns.tsx │ │ ├── Inline │ │ │ ├── Inline.docs.tsx │ │ │ ├── Inline.examples.tsx │ │ │ └── Inline.tsx │ │ ├── Input │ │ │ ├── Input.css.ts │ │ │ ├── Input.docs.tsx │ │ │ ├── Input.examples.tsx │ │ │ └── Input.tsx │ │ ├── Inset │ │ │ ├── Inset.docs.tsx │ │ │ ├── Inset.examples.tsx │ │ │ └── Inset.tsx │ │ ├── Lens │ │ │ ├── Lens.css.ts │ │ │ └── Lens.tsx │ │ ├── NudgeBanner │ │ │ └── NudgeBanner.tsx │ │ ├── Prompt │ │ │ └── Prompt.tsx │ │ ├── Rows │ │ │ ├── Rows.css.ts │ │ │ ├── Rows.docs.tsx │ │ │ ├── Rows.examples.tsx │ │ │ └── Rows.tsx │ │ ├── SVG │ │ │ └── SvgSmoothing.tsx │ │ ├── Separator │ │ │ ├── Separator.css.ts │ │ │ ├── Separator.docs.tsx │ │ │ ├── Separator.examples.tsx │ │ │ └── Separator.tsx │ │ ├── Skeleton │ │ │ ├── Skeleton.css.ts │ │ │ └── Skeleton.tsx │ │ ├── Stack │ │ │ ├── Stack.docs.tsx │ │ │ ├── Stack.examples.tsx │ │ │ └── Stack.tsx │ │ ├── Symbol │ │ │ ├── Symbol.css.ts │ │ │ ├── Symbol.docs.tsx │ │ │ ├── Symbol.examples.tsx │ │ │ ├── Symbol.tsx │ │ │ └── gradients.tsx │ │ ├── Text │ │ │ ├── Text.css.ts │ │ │ ├── Text.docs.tsx │ │ │ └── Text.tsx │ │ ├── TextLink │ │ │ └── TextLink.tsx │ │ ├── TextOverflow │ │ │ └── TextOverflow.tsx │ │ └── Toggle │ │ │ └── Toggle.tsx │ ├── docs │ │ ├── .eslintignore │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── .playroom │ │ │ ├── FrameComponent.js │ │ │ ├── components.ts │ │ │ ├── global.css.ts │ │ │ └── themes.ts │ │ ├── .prettierrc.js │ │ ├── README.md │ │ ├── assets.d.ts │ │ ├── babel.config.js │ │ ├── components │ │ │ ├── Button.tsx │ │ │ ├── ButtonLink.tsx │ │ │ ├── Code.css.ts │ │ │ ├── Code.tsx │ │ │ ├── CodeBlock.tsx │ │ │ ├── CodePreview.css.ts │ │ │ ├── CodePreview.tsx │ │ │ ├── Paragraph.tsx │ │ │ ├── Placeholder.tsx │ │ │ ├── TextInline.tsx │ │ │ ├── TextLink.css.ts │ │ │ └── TextLink.tsx │ │ ├── createDocs.ts │ │ ├── docs.ts │ │ ├── hooks │ │ │ └── useTheme.ts │ │ ├── icons │ │ │ ├── CheckIcon.tsx │ │ │ ├── ChevronDownIcon.tsx │ │ │ ├── ChevronUpIcon.tsx │ │ │ ├── CopyIcon.tsx │ │ │ ├── MoonIcon.tsx │ │ │ ├── PlayIcon.tsx │ │ │ └── SunIcon.tsx │ │ ├── next.config.js │ │ ├── package.json │ │ ├── pages │ │ │ ├── [category] │ │ │ │ └── [component].tsx │ │ │ ├── _app.tsx │ │ │ ├── _document.tsx │ │ │ └── index.tsx │ │ ├── playroom.config.js │ │ ├── public │ │ │ ├── 10a057a19c05e5222c23e27f8721e315.woff2 │ │ │ ├── 7d078eef80cc7bd36f5d2634b94302c2.woff2 │ │ │ ├── SFMonoMedium.woff │ │ │ ├── a10063243e691df6f06e65b34da0fe66.woff2 │ │ │ ├── a3d1d0ad4ba794e2473f30fac79196dc.woff2 │ │ │ ├── cf4fe3e1b6836782be2dd5f5399cd86d.woff2 │ │ │ ├── favicon.ico │ │ │ ├── initThemingBody.mjs │ │ │ ├── initThemingCritical.mjs │ │ │ ├── rainbow-icon@128w.png │ │ │ ├── rainbow-icon@256w.png │ │ │ ├── rainbow-icon@512w.png │ │ │ └── vercel.svg │ │ ├── styles │ │ │ ├── app.css.ts │ │ │ └── global.css.ts │ │ ├── tsconfig.json │ │ ├── types.ts │ │ ├── utils │ │ │ ├── codeTheme.ts │ │ │ ├── getSourceFromExample.ts │ │ │ ├── source.macro.d.ts │ │ │ └── source.macro.js │ │ └── yarn.lock │ ├── index.ts │ ├── scripts │ │ └── generateSymbols.ts │ ├── styles │ │ ├── autocompleteInputStyles.css.ts │ │ ├── color.docs.tsx │ │ ├── core.css.ts │ │ ├── designTokens.ts │ │ ├── fonts │ │ │ ├── SFMono-bold.woff2 │ │ │ ├── SFMono-semibold.woff2 │ │ │ ├── subset-SFRounded-Bold.woff2 │ │ │ ├── subset-SFRounded-Heavy.woff2 │ │ │ ├── subset-SFRounded-Medium.woff2 │ │ │ ├── subset-SFRounded-Regular.woff2 │ │ │ └── subset-SFRounded-Semibold.woff2 │ │ ├── hslObjectForColor.ts │ │ ├── initThemingBody.ts │ │ ├── initThemingCritical.ts │ │ ├── initThemingLocal.ts │ │ ├── radii.docs.tsx │ │ ├── rowTransparentAccentHighlight.css.ts │ │ ├── shadows.docs.tsx │ │ ├── spacing.docs.tsx │ │ ├── theme.ts │ │ └── typography.docs.tsx │ └── symbols │ │ ├── generated │ │ ├── index.ts │ │ └── types.ts │ │ └── sources │ │ ├── SF-Pro-Italic.ttf │ │ ├── SF-Pro-Text-Black.otf │ │ ├── SF-Pro-Text-Bold.otf │ │ ├── SF-Pro-Text-Heavy.otf │ │ ├── SF-Pro-Text-Light.otf │ │ ├── SF-Pro-Text-Medium.otf │ │ ├── SF-Pro-Text-Regular.otf │ │ ├── SF-Pro-Text-Semibold.otf │ │ ├── SF-Pro-Text-Thin.otf │ │ ├── SF-Pro-Text-Ultralight.otf │ │ ├── SF-Pro.ttf │ │ ├── chars.txt │ │ └── names.txt ├── entries │ ├── background │ │ ├── handlers │ │ │ ├── handleDisconnect.ts │ │ │ ├── handleInstallExtension.ts │ │ │ ├── handleKeepAlive.ts │ │ │ ├── handleOpenExtensionShortcut.ts │ │ │ ├── handlePrefetchMetadata.ts │ │ │ ├── handleProviderRequest.ts │ │ │ ├── handleSetupInpage.ts │ │ │ ├── handleTabAndWindowUpdates.ts │ │ │ └── handleWallets.ts │ │ └── index.ts │ ├── content │ │ └── index.ts │ ├── iframe │ │ ├── index.ts │ │ └── notification.tsx │ ├── inpage │ │ └── index.ts │ └── popup │ │ ├── App.test.disabled.tsx │ │ ├── App.tsx │ │ ├── ProtectedRoute.tsx │ │ ├── Routes.tsx │ │ ├── app.css.ts │ │ ├── components │ │ ├── AccountItem │ │ │ └── AccountItem.tsx │ │ ├── AccountName │ │ │ └── AccountName.tsx │ │ ├── AddressDisplay.tsx │ │ ├── AddressOrEns │ │ │ └── AddressorEns.tsx │ │ ├── AddressPill │ │ │ └── AddressPill.tsx │ │ ├── AppConnection │ │ │ ├── AppConnectionNudgeBanner.tsx │ │ │ ├── AppConnectionNudgeSheet.tsx │ │ │ ├── AppConnectionWalletItem │ │ │ │ ├── AppConnectionWalletItem.css.ts │ │ │ │ ├── AppConnectionWalletItem.tsx │ │ │ │ └── AppConnectionWalletItemDropdownMenu.tsx │ │ │ ├── AppConnectionWalletSwitcher.tsx │ │ │ └── AppConnectionWatcher.tsx │ │ ├── AppConnectionMenu │ │ │ ├── AppConnectionMenu.tsx │ │ │ ├── AppConnectionMenuHeader.tsx │ │ │ └── AppInteractionItem.tsx │ │ ├── AssetContextMenu.tsx │ │ ├── Asterisks │ │ │ └── Asterisks.tsx │ │ ├── Autocomplete │ │ │ └── index.tsx │ │ ├── Avatar │ │ │ └── Avatar.tsx │ │ ├── BackupReminder │ │ │ └── BackupReminder.tsx │ │ ├── Buy │ │ │ ├── ProviderCard.tsx │ │ │ └── utils.ts │ │ ├── BuyIcon │ │ │ └── BuyIcon.tsx │ │ ├── ChainBadge │ │ │ └── ChainBadge.tsx │ │ ├── Checkbox │ │ │ └── Checkbox.tsx │ │ ├── ChevronDown │ │ │ └── ChevronDown.tsx │ │ ├── ChevronRight │ │ │ └── index.tsx │ │ ├── ChevronRightDouble │ │ │ └── index.tsx │ │ ├── ChevronSwitcher │ │ │ └── ChevronSwitcher.tsx │ │ ├── CoinIcon │ │ │ ├── CoinIcon.css.ts │ │ │ ├── CoinIcon.tsx │ │ │ └── ContractInteractionIcon.tsx │ │ ├── CoinRow │ │ │ └── CoinRow.tsx │ │ ├── CoinbaseIcon │ │ │ └── CoinbaseIcon.tsx │ │ ├── CommandK │ │ │ ├── AnimatedLoadingBar.tsx │ │ │ ├── CommandK.tsx │ │ │ ├── CommandKList.tsx │ │ │ ├── CommandKModal.tsx │ │ │ ├── CommandKStyles.css.ts │ │ │ ├── CommandKToolbar.tsx │ │ │ ├── CommandRows.tsx │ │ │ ├── SearchItems.ts │ │ │ ├── pageConfig.ts │ │ │ ├── references.ts │ │ │ ├── useCommandKNavigation.ts │ │ │ ├── useCommandKStatus.tsx │ │ │ ├── useCommands.tsx │ │ │ ├── useSearchableContacts.ts │ │ │ ├── useSearchableENSOrAddress.ts │ │ │ ├── useSearchableNFTs.ts │ │ │ ├── useSearchableTokens.ts │ │ │ ├── useSearchableWallets.ts │ │ │ └── utils.ts │ │ ├── ContextMenu │ │ │ └── ContextMenu.tsx │ │ ├── DappIcon │ │ │ └── DappIcon.tsx │ │ ├── DetailsMenu │ │ │ └── index.tsx │ │ ├── Draggable │ │ │ ├── draggableItem.css.ts │ │ │ └── index.tsx │ │ ├── DropdownInputWrapper │ │ │ └── DropdownInputWrapper.tsx │ │ ├── DropdownMenu │ │ │ ├── DropdownMenu.tsx │ │ │ ├── DropdownSubMenu.tsx │ │ │ └── RadioItemHighlightWrapper.css.ts │ │ ├── EthSymbol │ │ │ └── EthSymbol.tsx │ │ ├── ExplainerSheet │ │ │ └── ExplainerSheet.tsx │ │ ├── ExternalImage │ │ │ └── ExternalImage.tsx │ │ ├── FlyingRainbows │ │ │ ├── FlyingRainbows.tsx │ │ │ └── utils.ts │ │ ├── Form │ │ │ ├── Form.tsx │ │ │ └── FormInput.tsx │ │ ├── FullScreen │ │ │ ├── FullScreenBackground.tsx │ │ │ └── FullScreenContainer.tsx │ │ ├── HWRequestListener │ │ │ └── HWRequestListener.tsx │ │ ├── HomeMenuRow │ │ │ └── HomeMenuRow.tsx │ │ ├── IconAndCopyList.tsx │ │ │ └── IconAndCopyList.tsx │ │ ├── Icons │ │ │ └── AppConnectionImageMask.svg │ │ ├── IdleTimer │ │ │ └── IdleTimer.tsx │ │ ├── ImportWallet │ │ │ ├── AccountToImportRows.tsx │ │ │ ├── ImportWallet.tsx │ │ │ ├── ImportWalletNavbar.tsx │ │ │ ├── ImportWalletSelection.tsx │ │ │ ├── ImportWalletSelectionEdit.tsx │ │ │ ├── ImportWalletViaPrivateKey.tsx │ │ │ ├── ImportWalletViaSeed.tsx │ │ │ └── useImportWalletSessionSecrets.tsx │ │ ├── ImportWalletTextarea │ │ │ └── ImportWalletTextarea.tsx │ │ ├── InputMask │ │ │ ├── GweiInputMask │ │ │ │ └── GweiInputMask.tsx │ │ │ ├── SendInputMask │ │ │ │ └── SendInputMask.tsx │ │ │ ├── SwapInputMask │ │ │ │ └── SwapInputMask.tsx │ │ │ ├── utils.test.ts │ │ │ └── utils.ts │ │ ├── LabelPill │ │ │ └── LabelPill.tsx │ │ ├── LedgerIcon │ │ │ └── LedgerIcon.tsx │ │ ├── Link │ │ │ └── Link.tsx │ │ ├── LogoWithLetters │ │ │ └── LogoWithLetters.tsx │ │ ├── Menu │ │ │ ├── Menu.tsx │ │ │ ├── MenuContainer.tsx │ │ │ └── MenuItem.tsx │ │ ├── MoonpayIcon │ │ │ └── MoonpayIcon.tsx │ │ ├── MoreInfoButton │ │ │ └── MoreInfoButton.tsx │ │ ├── Navbar │ │ │ ├── Navbar.css.ts │ │ │ └── Navbar.tsx │ │ ├── OnboardMenu │ │ │ └── OnboardMenu.tsx │ │ ├── OnboardingKeepAlive │ │ │ └── index.tsx │ │ ├── PasswordInput │ │ │ └── PasswordInput.tsx │ │ ├── QuickPromo │ │ │ └── QuickPromo.tsx │ │ ├── Rainbow3dLogo.tsx │ │ ├── RampIcon │ │ │ └── RampIcon.tsx │ │ ├── SeedPhraseTable │ │ │ └── SeedPhraseTable.tsx │ │ ├── SeedVerifyQuiz │ │ │ └── SeedVerifyQuiz.tsx │ │ ├── ShortcutHint │ │ │ └── ShortcutHint.tsx │ │ ├── SideChainExplainer.tsx │ │ ├── Spinner │ │ │ ├── Spinner.css.ts │ │ │ └── Spinner.tsx │ │ ├── SpinnerRow │ │ │ └── SpinnerRow.tsx │ │ ├── SwitchMenu │ │ │ ├── ConnectedAppNetworkMenu.tsx │ │ │ ├── SwitchMenu.tsx │ │ │ └── SwitchNetworkMenu.tsx │ │ ├── Tabs │ │ │ ├── TabBar.tsx │ │ │ ├── TabIcons │ │ │ │ ├── Activity.tsx │ │ │ │ ├── ActivitySelected.tsx │ │ │ │ ├── Home.tsx │ │ │ │ ├── HomeSelected.tsx │ │ │ │ ├── NFTs.tsx │ │ │ │ ├── NFTsSelected.tsx │ │ │ │ ├── Points.tsx │ │ │ │ └── PointsSelected.tsx │ │ │ └── Tabs.tsx │ │ ├── Tag.tsx │ │ ├── TestnetMode │ │ │ ├── TestnetBar │ │ │ │ ├── TestnetBar.tsx │ │ │ │ └── TestnetBarBackground.tsx │ │ │ └── TestnetModeWatcher │ │ │ │ └── TestnetModeWatcher.tsx │ │ ├── Toast │ │ │ └── Toast.tsx │ │ ├── Tooltip │ │ │ └── CursorTooltip.tsx │ │ ├── TransactionFee │ │ │ ├── CustomGasSheet.tsx │ │ │ ├── TransactionFee.tsx │ │ │ └── TransactionSpeedsMenu.tsx │ │ ├── TrezorIcon │ │ │ └── TrezorIcon.tsx │ │ ├── UnsupportedBrowserSheet.tsx │ │ ├── ViewSecret │ │ │ └── ViewSecret.tsx │ │ ├── WalletAvatar │ │ │ └── WalletAvatar.tsx │ │ ├── WalletContextMenu.tsx │ │ ├── WalletIcon │ │ │ └── WalletIcon.tsx │ │ ├── WarningInfo │ │ │ ├── WalletWipeWarningInfo.tsx │ │ │ ├── WarningInfo.tsx │ │ │ └── walletGroupWipeWarningInfo.tsx │ │ ├── WatchWallet │ │ │ └── WatchWallet.tsx │ │ ├── WindowStroke │ │ │ └── WindowStroke.tsx │ │ └── _dev │ │ │ └── ClearStorage.tsx │ │ ├── global.css.ts │ │ ├── handlers │ │ ├── imgix.ts │ │ ├── importWalletSecrets.ts │ │ ├── ledger.ts │ │ ├── trezor.ts │ │ ├── wallet.ts │ │ ├── walletAction.ts │ │ └── walletVariables.tsx │ │ ├── hooks │ │ ├── approveAppRequest │ │ │ └── useApproveAppRequestValidations.ts │ │ ├── send │ │ │ ├── useAllFilteredWallets.ts │ │ │ ├── useSendAsset.ts │ │ │ ├── useSendInputs.ts │ │ │ ├── useSendState.ts │ │ │ ├── useSendUniqueAsset.ts │ │ │ └── useSendValidations.ts │ │ ├── swap │ │ │ ├── analyticsTrackQuoteFailed.ts │ │ │ ├── index.tsx │ │ │ ├── useSwapAssets.ts │ │ │ ├── useSwapDropdownDimensions.tsx │ │ │ ├── useSwapInputs.ts │ │ │ ├── useSwapNativeAmounts.tsx │ │ │ ├── useSwapPriceImpact.tsx │ │ │ ├── useSwapQuote.ts │ │ │ ├── useSwapQuoteHandler.ts │ │ │ ├── useSwapReviewDetails.ts │ │ │ ├── useSwapSettings.ts │ │ │ ├── useSwapSlippage.tsx │ │ │ └── useSwapValidations.ts │ │ ├── useAccounts.ts │ │ ├── useActiveTab.ts │ │ ├── useActivityShortcuts.ts │ │ ├── useAppSession.ts │ │ ├── useAppSessions.ts │ │ ├── useAuth.tsx │ │ ├── useAvatar.ts │ │ ├── useBrowser.ts │ │ ├── useCommandKInternalShortcuts.ts │ │ ├── useCommandKShortcuts.ts │ │ ├── useComponentWillUnmount.ts │ │ ├── useContacts.ts │ │ ├── useCoolMode.ts │ │ ├── useCurrentHomeSheet.tsx │ │ ├── useCurrentWalletType.tsx │ │ ├── useCustomNetworkAsset.ts │ │ ├── useDebounce.ts │ │ ├── useDefaultTxSpeed.ts │ │ ├── useDeviceUUID.ts │ │ ├── useDominantColor.ts │ │ ├── useEnhanceWithEnsNames.ts │ │ ├── useEns.ts │ │ ├── useExpiryListener.ts │ │ ├── useFavoriteAssets.ts │ │ ├── useGas.ts │ │ ├── useHomePromptsQueue.ts │ │ ├── useHomeShortcuts.ts │ │ ├── useInfiniteTransactionList.ts │ │ ├── useIsFullScreen.ts │ │ ├── useKeyboardAnalytics.ts │ │ ├── useKeyboardShortcut.ts │ │ ├── useNativeAsset.ts │ │ ├── useNativeAssetForNetwork.ts │ │ ├── useNativeAssets.ts │ │ ├── useNavigateToSwaps.tsx │ │ ├── useNftShortcuts.tsx │ │ ├── usePendingTransactionWatcher.ts │ │ ├── usePoll.ts │ │ ├── usePress.ts │ │ ├── usePrevious.ts │ │ ├── useRainbowNavigate.ts │ │ ├── useRestoreNavigation.ts │ │ ├── useScroll.ts │ │ ├── useScrollLock.ts │ │ ├── useSearchCurrencyLists.ts │ │ ├── useSwitchWalletShortcuts.ts │ │ ├── useSystemSpecificModifierKey.ts │ │ ├── useTimeout.ts │ │ ├── useTokenDetailsShortcuts.ts │ │ ├── useTokenListSampling.ts │ │ ├── useTokenPressMouseEvents.ts │ │ ├── useTokensShortcuts.ts │ │ ├── useTransactionListForPendingTxs.ts │ │ ├── useTranslationContext.ts │ │ ├── useUserAsset.ts │ │ ├── useUserAssetsBalance.ts │ │ ├── useUserChains.ts │ │ ├── useUserNativeAsset.ts │ │ ├── useVirtualizedAssets.ts │ │ ├── useVisibleTokenCount.ts │ │ ├── useWalletBackups.ts │ │ ├── useWalletInfo.ts │ │ ├── useWalletName.ts │ │ ├── useWallets.ts │ │ ├── useWalletsFromKeychain.ts │ │ ├── useWalletsSummary.ts │ │ └── useWatchPendingTransactions.ts │ │ ├── index.html │ │ ├── index.ts │ │ ├── layouts │ │ ├── MainLayout.tsx │ │ └── StickyHeader.tsx │ │ ├── pages │ │ ├── _playgrounds │ │ │ ├── default.tsx │ │ │ ├── ds.tsx │ │ │ └── index.tsx │ │ ├── buy │ │ │ └── index.tsx │ │ ├── createPassword │ │ │ └── index.tsx │ │ ├── home │ │ │ ├── Activity │ │ │ │ ├── ActivitiesList.tsx │ │ │ │ ├── ActivityContextMenu.tsx │ │ │ │ ├── ActivityDetails.tsx │ │ │ │ ├── ActivityIcon.tsx │ │ │ │ ├── ActivityPill.css.ts │ │ │ │ ├── ActivityPill.tsx │ │ │ │ ├── ActivityTypeIcon.tsx │ │ │ │ ├── ActivityValue.tsx │ │ │ │ └── NoActivity.tsx │ │ │ ├── Approvals │ │ │ │ ├── Approvals.css.ts │ │ │ │ ├── Approvals.tsx │ │ │ │ ├── RevokeApproval.tsx │ │ │ │ ├── RevokeApprovalSheet.tsx │ │ │ │ └── utils.tsx │ │ │ ├── ConnectedApps.tsx │ │ │ ├── Header.tsx │ │ │ ├── MoreMenu.tsx │ │ │ ├── NFTs │ │ │ │ ├── BirdIcon.tsx │ │ │ │ ├── DisplayModeDropdown.tsx │ │ │ │ ├── NFTCollectionSection.tsx │ │ │ │ ├── NFTCollections.tsx │ │ │ │ ├── NFTContextMenu.tsx │ │ │ │ ├── NFTDetails.tsx │ │ │ │ ├── NFTDropdownMenu.tsx │ │ │ │ ├── NFTGallery.tsx │ │ │ │ ├── NFTThumbnail.tsx │ │ │ │ ├── NFTs.css.ts │ │ │ │ ├── NFTs.tsx │ │ │ │ ├── NftsEmptyState.tsx │ │ │ │ ├── SortDropdown.tsx │ │ │ │ └── utils.ts │ │ │ ├── NetworkMenu.tsx │ │ │ ├── PageHeader.css.ts │ │ │ ├── Points │ │ │ │ ├── AirdropIcon.tsx │ │ │ │ ├── ClaimOverview.tsx │ │ │ │ ├── ClaimSheet.tsx │ │ │ │ ├── ConsoleText.tsx │ │ │ │ ├── OldPointsDashboard.tsx │ │ │ │ ├── Points.tsx │ │ │ │ ├── PointsDashboard.tsx │ │ │ │ ├── PointsOnboardingSheet.tsx │ │ │ │ ├── PointsReferralSheet.tsx │ │ │ │ ├── WeeklyPointsOverview.tsx │ │ │ │ ├── references.ts │ │ │ │ ├── usePoints.ts │ │ │ │ ├── usePointsChallenge.tsx │ │ │ │ ├── useReferralCodeValidation.tsx │ │ │ │ └── utils.ts │ │ │ ├── Skeletons.tsx │ │ │ ├── TabHeader.tsx │ │ │ ├── TokenDetails │ │ │ │ ├── About.tsx │ │ │ │ ├── Approvals.tsx │ │ │ │ ├── LineChart.tsx │ │ │ │ ├── PriceChart.tsx │ │ │ │ ├── TokenContextMenu.tsx │ │ │ │ ├── TokenDetails.tsx │ │ │ │ ├── monotoneCubicInterpolation.ts │ │ │ │ └── useTokenInfo.ts │ │ │ ├── TokenMarkedHighlighter.tsx │ │ │ ├── Tokens.tsx │ │ │ └── index.tsx │ │ ├── hw │ │ │ ├── addByIndexSheet.tsx │ │ │ ├── chooseHW.tsx │ │ │ ├── ledger.tsx │ │ │ ├── success.tsx │ │ │ ├── trezor.tsx │ │ │ └── walletList │ │ │ │ ├── AccountIndex.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── walletList.css.ts │ │ ├── importOrConnect │ │ │ └── index.tsx │ │ ├── importWallet │ │ │ └── index.tsx │ │ ├── importWalletSelection │ │ │ └── index.tsx │ │ ├── messages │ │ │ ├── AccountSigningWith.tsx │ │ │ ├── AddEthereumChain │ │ │ │ ├── AddEthereumChainActions.tsx │ │ │ │ ├── AddEthereumChainInfo.tsx │ │ │ │ └── index.tsx │ │ │ ├── ApproveAppRequest.tsx │ │ │ ├── BottomActions │ │ │ │ └── index.tsx │ │ │ ├── DappScanStatus.tsx │ │ │ ├── OverflowGradient.css.ts │ │ │ ├── RequestAccounts │ │ │ │ ├── RequestAccountsActions.tsx │ │ │ │ ├── RequestAccountsInfo.tsx │ │ │ │ └── index.tsx │ │ │ ├── SendTransaction │ │ │ │ ├── SendTransactionActions.tsx │ │ │ │ ├── SendTransactionsInfo.tsx │ │ │ │ └── index.tsx │ │ │ ├── SignMessage │ │ │ │ ├── SignMessageActions.tsx │ │ │ │ ├── SignMessageInfo.tsx │ │ │ │ └── index.tsx │ │ │ ├── Simulation.tsx │ │ │ ├── Tabs.tsx │ │ │ ├── WatchAsset │ │ │ │ ├── WatchAssetActions.tsx │ │ │ │ ├── WatchAssetInfo.tsx │ │ │ │ └── index.tsx │ │ │ ├── useHasEnoughGas.ts │ │ │ └── useSimulateTransaction.tsx │ │ ├── qrcode │ │ │ ├── index.tsx │ │ │ └── qrcode.tsx │ │ ├── rootHandler │ │ │ └── RootHandler.tsx │ │ ├── seedBackupPrompt │ │ │ └── index.tsx │ │ ├── seedReveal │ │ │ └── index.tsx │ │ ├── seedVerify │ │ │ └── index.tsx │ │ ├── send │ │ │ ├── ContactPrompt.tsx │ │ │ ├── InputActionButton.tsx │ │ │ ├── NavbarContactButton.tsx │ │ │ ├── ReviewSheet.tsx │ │ │ ├── RowHighlightWrapper.tsx │ │ │ ├── SendTokenInput.tsx │ │ │ ├── ToAddressInput.css.ts │ │ │ ├── ToAddressInput.tsx │ │ │ ├── ValueInput.tsx │ │ │ └── index.tsx │ │ ├── settings │ │ │ ├── currency.tsx │ │ │ ├── customChain │ │ │ │ ├── addAsset.tsx │ │ │ │ └── index.tsx │ │ │ ├── language.tsx │ │ │ ├── networks.tsx │ │ │ ├── privacy │ │ │ │ ├── autoLockTimer.tsx │ │ │ │ ├── changePassword.tsx │ │ │ │ ├── confirmPasswordPrompt.tsx │ │ │ │ └── privacy.tsx │ │ │ ├── rpcs.tsx │ │ │ ├── settings.tsx │ │ │ ├── transactions.tsx │ │ │ └── walletsAndKeys │ │ │ │ ├── hardwareWalletWipePrompt.tsx │ │ │ │ ├── privateKey │ │ │ │ ├── privateKey.tsx │ │ │ │ └── warning.tsx │ │ │ │ ├── recoveryPhrase │ │ │ │ ├── recoveryPhrase.tsx │ │ │ │ ├── recoveryPhraseVerify.tsx │ │ │ │ └── warning.tsx │ │ │ │ ├── walletDetails.tsx │ │ │ │ ├── walletGroupWipePrompt.tsx │ │ │ │ ├── walletWipePrompt.tsx │ │ │ │ ├── walletsAndKeys.tsx │ │ │ │ ├── wipeWalletGroupWarning.tsx │ │ │ │ └── wipeWalletWarning.tsx │ │ ├── sign │ │ │ └── index.tsx │ │ ├── speedUpAndCancelSheet │ │ │ └── index.tsx │ │ ├── swap │ │ │ ├── SlippageInputMask.tsx │ │ │ ├── SwapInputActionButton.tsx │ │ │ ├── SwapReviewSheet │ │ │ │ ├── SwapAssetCard.tsx │ │ │ │ ├── SwapReviewSheet.tsx │ │ │ │ ├── SwapRoutes.tsx │ │ │ │ └── SwapViewContractDropdown.tsx │ │ │ ├── SwapSettings │ │ │ │ ├── SwapRouteDropdownMenu.tsx │ │ │ │ └── SwapSettings.tsx │ │ │ ├── SwapTokenInput.css.ts │ │ │ ├── SwapTokenInput │ │ │ │ ├── TokenDropdown │ │ │ │ │ ├── TokenToBuyDropdown.tsx │ │ │ │ │ ├── TokenToBuySection.tsx │ │ │ │ │ └── TokenToSellDropdown.tsx │ │ │ │ ├── TokenInfo │ │ │ │ │ ├── TokenToBuyInfo.tsx │ │ │ │ │ └── TokenToSellInfo.tsx │ │ │ │ ├── TokenInput.tsx │ │ │ │ ├── TokenRow │ │ │ │ │ ├── RowHighlightWrapper.tsx │ │ │ │ │ ├── TokenToBuyRow.tsx │ │ │ │ │ └── TokenToSellRow.tsx │ │ │ │ ├── TokenToBuyInput.tsx │ │ │ │ └── TokenToSellInput.tsx │ │ │ ├── index.tsx │ │ │ ├── onSwap.tsx │ │ │ ├── swapTimeEstimate.ts │ │ │ ├── useSwapButton.tsx │ │ │ └── utils.ts │ │ ├── unlock │ │ │ └── index.tsx │ │ ├── walletReady │ │ │ ├── ReadyHotkeys │ │ │ │ ├── OpenText.tsx │ │ │ │ ├── OptionAltPress.tsx │ │ │ │ ├── RPress.tsx │ │ │ │ ├── ShiftPress.tsx │ │ │ │ └── pressTransitions.css.ts │ │ │ ├── ReadyShortcut.tsx │ │ │ └── index.tsx │ │ ├── walletSwitcher │ │ │ ├── addWallet.tsx │ │ │ ├── chooseWalletGroup.tsx │ │ │ ├── createWalletPrompt.tsx │ │ │ ├── index.tsx │ │ │ ├── newImportWallet.tsx │ │ │ ├── newImportWalletSelection.tsx │ │ │ ├── newWatchWallet.tsx │ │ │ ├── removeWalletPrompt.tsx │ │ │ └── renameWalletPrompt.tsx │ │ ├── wallets │ │ │ └── index.tsx │ │ ├── watchWallet │ │ │ └── index.tsx │ │ └── welcome │ │ │ ├── ImportOrCreateWallet.tsx │ │ │ ├── OnboardBeforeConnectSheet.tsx │ │ │ └── index.tsx │ │ ├── urls.ts │ │ └── utils │ │ ├── activeElement.ts │ │ ├── chunkLinks.ts │ │ ├── clickHeader.ts │ │ ├── emojiAvatarBackgroundColors.ts │ │ ├── emojiAvatarForAddress.ts │ │ ├── isMobile.ts │ │ ├── memoFn.ts │ │ ├── mergeRefs.ts │ │ ├── passwords.ts │ │ ├── playSound.ts │ │ ├── pseudoRandomArrayItemFromString.ts │ │ ├── search.ts │ │ ├── simulateClick.ts │ │ ├── simulateTab.ts │ │ ├── tabIndexes.ts │ │ ├── windows.ts │ │ └── zIndexes.ts ├── logger │ ├── README.md │ ├── debugContext.ts │ └── index.ts └── test │ ├── setup.ts │ └── utils.ts ├── static ├── _locales │ ├── ar │ │ └── messages.json │ ├── en_US │ │ └── messages.json │ ├── es_419 │ │ └── messages.json │ ├── fr │ │ └── messages.json │ ├── hi │ │ └── messages.json │ ├── id │ │ └── messages.json │ ├── ja │ │ └── messages.json │ ├── ko │ │ └── messages.json │ ├── pt_BR │ │ └── messages.json │ ├── ru │ │ └── messages.json │ ├── th │ │ └── messages.json │ ├── tr │ │ └── messages.json │ └── zh_CN │ │ └── messages.json ├── allowlist.json ├── assets │ ├── aggregators │ │ ├── 0x.png │ │ ├── 1inch.png │ │ └── rainbow.png │ ├── appConnectionImageMask.svg │ ├── appConnectionSheetImageMask.svg │ ├── appConnectionWalletItemImageMask.svg │ ├── appsConnectedImageMask.svg │ ├── audio │ │ ├── correct_seed_quiz.mp3 │ │ ├── incorrect_seed_quiz.mp3 │ │ ├── ui_lock.mp3 │ │ ├── ui_unlock.mp3 │ │ └── woosh.mp3 │ ├── bg │ │ └── noise.png │ ├── ethIcon.png │ ├── hardhwareWalletAvatarImageMask.svg │ ├── hw │ │ ├── ledger-device-eth.png │ │ ├── ledger-device-unlock.png │ │ ├── ledger-device.png │ │ ├── ledger-logo.png │ │ ├── trezor-device.png │ │ └── trezor-logo.png │ ├── masks │ │ └── pending_mask.png │ ├── onboarding │ │ ├── dark_alt_bottom@2x.png │ │ ├── dark_alt_pressed_bottom@2x.png │ │ ├── dark_alt_pressed_top@2x.png │ │ ├── dark_alt_top@2x.png │ │ ├── dark_option_bottom@2x.png │ │ ├── dark_option_pressed_bottom@2x.png │ │ ├── dark_option_pressed_top@2x.png │ │ ├── dark_option_top@2x.png │ │ ├── dark_r_bottom@2x.png │ │ ├── dark_r_pressed_bottom@2x.png │ │ ├── dark_r_pressed_top@2x.png │ │ ├── dark_r_top@2x.png │ │ ├── dark_shift_bottom@2x.png │ │ ├── dark_shift_pressed_bottom@2x.png │ │ ├── dark_shift_pressed_top@2x.png │ │ ├── dark_shift_top@2x.png │ │ ├── light_alt_bottom@2x.png │ │ ├── light_alt_pressed_bottom@2x.png │ │ ├── light_alt_pressed_top@2x.png │ │ ├── light_alt_top@2x.png │ │ ├── light_option_bottom@2x.png │ │ ├── light_option_pressed_bottom@2x.png │ │ ├── light_option_pressed_top@2x.png │ │ ├── light_option_top@2x.png │ │ ├── light_r_bottom@2x.png │ │ ├── light_r_pressed_bottom@2x.png │ │ ├── light_r_pressed_top@2x.png │ │ ├── light_r_top@2x.png │ │ ├── light_shift_bottom@2x.png │ │ ├── light_shift_pressed_bottom@2x.png │ │ ├── light_shift_pressed_top@2x.png │ │ └── light_shift_top@2x.png │ ├── rainbow │ │ ├── light-rainbow.png │ │ ├── light-rainbow@2x.png │ │ ├── neon-rainbow.png │ │ ├── neon-rainbow@2x.png │ │ ├── og-rainbow.png │ │ ├── og-rainbow@2x.png │ │ ├── pixel-rainbow.png │ │ ├── pixel-rainbow@2x.png │ │ ├── rainbow-logo-light.png │ │ ├── rainbow-logo-light@2x.png │ │ ├── rainbow-logo.png │ │ ├── rainbow-logo@2x.png │ │ ├── white-rainbow.png │ │ └── white-rainbow@2x.png │ └── unsupportedBrowserIcon.svg ├── images │ ├── icon-16.png │ ├── icon-16@2x.png │ ├── icon-16@32x.png │ ├── icon-16@4x.png │ ├── icon-16@8x.png │ ├── icon-19.png │ └── icon-19@2x.png ├── json │ ├── abis │ │ ├── method-registry-abi.json │ │ └── optimism-gas-oracle-abi.json │ └── languages │ │ ├── ar_AR.json │ │ ├── en_US.json │ │ ├── es_419.json │ │ ├── fr_FR.json │ │ ├── hi_IN.json │ │ ├── id_ID.json │ │ ├── ja_JP.json │ │ ├── ko_KR.json │ │ ├── pt_BR.json │ │ ├── ru_RU.json │ │ ├── th_TH.json │ │ ├── tr_TR.json │ │ └── zh_CN.json ├── manifest.json ├── theming.js ├── themingBody.js ├── trezor-usb-permissions.html └── vendor │ ├── trezor-content-script.js │ └── trezor-usb-permissions.js ├── tsconfig.json ├── vitest.config.ts ├── webpack.config.dev.js ├── webpack.config.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | docs/ 3 | .env.d.ts 4 | scripts/ 5 | static/ 6 | src/core/graphql/__generated__/ 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Fixes BX-#### 2 | Figma link (if any): 3 | 4 | ## What changed (plus any additional context for devs) 5 | 6 | ## Screen recordings / screenshots 7 | 8 | 9 | 10 | ## What to test 11 | 12 | 21 | -------------------------------------------------------------------------------- /.github/actions/chromeTestsSetup/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Chrome tests setup' 2 | description: 'runs Chrome tests setup' 3 | inputs: 4 | gh-access-token: 5 | description: 'Github Access Token' 6 | required: true 7 | runs: 8 | using: 'composite' 9 | steps: 10 | - uses: ./.github/actions/testsSetup 11 | with: 12 | gh-access-token: ${{ inputs.gh-access-token }} 13 | - name: Install chrome 14 | shell: 'bash' 15 | run: npx @puppeteer/browsers install chrome@133 16 | -------------------------------------------------------------------------------- /.github/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/.github/hero.png -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | name: Automatic Rebase 2 | on: 3 | issue_comment: 4 | types: [created] 5 | jobs: 6 | rebase: 7 | name: Rebase 8 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') && github.event.comment.author_association == 'MEMBER' 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout the latest code 12 | uses: actions/checkout@v4 13 | with: 14 | token: ${{ secrets.GITHUB_TOKEN }} 15 | fetch-depth: 0 # otherwise, you will fail to push refs to dest repo 16 | - name: Automatic Rebase 17 | uses: cirrus-actions/rebase@1.6 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .env-e 3 | .DS_Store 4 | 5 | # node.js 6 | # 7 | node_modules/ 8 | npm-debug.log 9 | yarn-error.log 10 | 11 | .eslintcache 12 | 13 | build/ 14 | screenshots/ 15 | 16 | # Anvil logs 17 | anvil*.log 18 | 19 | rainbowbx.xpi 20 | 21 | .idea/** 22 | 23 | static/data -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install lint-staged 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.16.0 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | build/ 2 | src/core/graphql/__generated__/ 3 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: "always", 3 | endOfLine: "lf", 4 | printWidth: 80, 5 | semi: true, 6 | singleQuote: true, 7 | tabWidth: 2, 8 | trailingComma: "all", 9 | }; 10 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | ignore-scripts true 2 | save-exact true -------------------------------------------------------------------------------- /README_FIREFOX.md: -------------------------------------------------------------------------------- 1 | # Rainbow Extension for Firefox 2 | 3 | ## Prerequisites 4 | 5 | - [yarn](https://classic.yarnpkg.com/en/docs/install) 6 | - [nvm](https://github.com/nvm-sh/nvm) 7 | 8 | ## Getting started on Firefox 9 | 10 | ### 1. Set up Node 11 | 12 | Use node v20 (20.16.0) or if you use nvm follow the instructions below 13 | 14 | ```bash 15 | nvm install 20.16.0 16 | # or 17 | nvm use 20.16.0 18 | ``` 19 | 20 | ### 2. Install project dependencies 21 | 22 | ```bash 23 | yarn setup 24 | ``` 25 | 26 | 27 | ### 3. Build the extension 28 | 29 | ```bash 30 | yarn firefox:build && yarn update-manifest:prod 31 | ``` 32 | 33 | ### 4. Generate bundle 34 | 35 | ```bash 36 | yarn zip && yarn firefox:zip 37 | ``` 38 | 39 | You should find a xpi file named `rainbowbx.xpi` in the root folder of this repository -------------------------------------------------------------------------------- /audit-ci.jsonc: -------------------------------------------------------------------------------- 1 | // audit-ci.jsonc 2 | { 3 | // $schema provides code completion hints to IDEs. 4 | "$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json", 5 | "moderate": true, 6 | "allowlist": [ 7 | "deep-object-diff", 8 | "GHSA-8x6c-cv3v-vp6g", 9 | "GHSA-653v-rqx9-j85p", 10 | "GHSA-p8p7-x288-28g6", 11 | "GHSA-776f-qx25-q3cc", 12 | "GHSA-f9xv-q969-pqx4", 13 | "GHSA-353f-5xf4-qw67", 14 | "GHSA-j8xg-fqg3-53r7", 15 | "GHSA-67hx-6x53-jw92", 16 | "GHSA-c24v-8rfc-w8vw", 17 | "GHSA-mgfv-m47x-4wqp", 18 | "GHSA-96g7-g7g9-jxw8", 19 | "GHSA-c76h-2ccp-4975", 20 | "GHSA-vg6x-rcgg-rjx6", 21 | "GHSA-67mh-4wv8-2f99", 22 | "GHSA-3gc7-fjrx-p6mg", 23 | "GHSA-cpj6-fhp6-mr6j", 24 | "GHSA-f46r-rw29-r322" 25 | ] 26 | } -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /static/json/languages/en_US.json 3 | translation: /static/json/languages/%locale_with_underscore%.json 4 | -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x038dce7884e70b272cd1e2451c7ac6c7acead26c6fbd4593ac6840211a966072.json: -------------------------------------------------------------------------------- 1 | {"error":true,"message":"Failed to fetch: Internal Server Error"} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x1fff3bc1f1da3704a60b836efa10528143a50bb300b9461457d46c445f5f439d.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x2522bc7da8c360a103d31c1941b2874c56de2ef59667a8347ca9dd9412b00323.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x2d17452c5f161d4c653a5f82922341249fe74c24c68b2598964074187873f2ed.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x2eb23074686a20f6e0cb064d999214d6e5a8da3995979e418f485bb55744c15d.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x38b342e1dabe2c1fc1fe8a752034c591a68e8a669e6742c7967770a95ec8ef76.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x4bbc11ada78a41c1d6988ddb4c961616ffda14648a6999609b05dfa8e0f23040.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x4bfecb6351d987a221ca103e06fbabc34c4a6fea57281318cc064f299f36413c.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x5bc1b94c5044bd672aec84cf0bb749a11c10eb73c2b2a393932fe283b46db182.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x75c48fb2f0c937df972f466d7ee5e66fa2475b9fa2a10a0a17e3d9719519ee87.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x7f2733a251e1a520c9811b6358e486d626d77e2a94319438381588727f374885.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x80859a5a4665bc984c08fbc08db3743c1005992a1d946a7e393ecaecdf54b634.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x81f456006fc8b4d42d0d8e99d45c951a8317dc2b29943b3fd6e913c722b9b178.json: -------------------------------------------------------------------------------- 1 | {"error":true,"message":"Failed to fetch: Internal Server Error"} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0x8de7fe00b0e00a66f07a660733aa2d931fb516d24ee2fb2a31d5ea109f17518a.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xa7d8182320bc29f6e1843019fe70885a8f485991693197745ae20023a99b0adb.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xa8851b608dc6212889006842c206dda15a1e718768e1d16afb87a69a2e04753c.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xaa0ad349da2ff82c83d4d9c770898312e46c68a34c0c0bc5c17732944b249bbf.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xd1f1a419f92e46057710f9f0c9617ef2b6a391229f1a73de98e4f4ef829b7bc7.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xd29876457b7fd7b56832bfd10a0af3ec343beb1d49a5213cbd69eab8cc9f7653.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xd93b0e4edf8ca955c914cc7ed4d9176834f8e7b9324cf26b724cc0f7345dbd39.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xdbc0f49ff7efb45dca12f62922f205e1e3324f0a693d40f6d0433ea681df9436.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xe1a1cb8f0c4bf8028c0330d096feb5e727d4c91a6a12cf2f6494cda55145e9df.json: -------------------------------------------------------------------------------- 1 | {"error":true,"message":"Failed to fetch: Internal Server Error"} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xea83715b8b512e5444577de7a315e51d157d1bd2b53bb1398c5af0ca98f1ad7e.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xf67dfbc6441947ed8384222e3dd88dbcf7b4a37bceef60a2f78dfbf06d71a23e.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xf6be4896f04adb2829a5edd8386ffb96d87c47a6beda5545d0b71edbfe204782.json: -------------------------------------------------------------------------------- 1 | {"error":true,"message":"Failed to fetch: Internal Server Error"} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xf7ef0fb43f50e89350d18de1fb4d1f99c2320f2f82efe312a8583250ce632527.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xf9fd9c875d226201534eb0afe98bc64b5aa76a30c04bdb629b8e5286b010d67d.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":2}} -------------------------------------------------------------------------------- /e2e/mocks/swap_quotes/0xfafa8443a4a3eabafe4a84a138a4762cc774ca5c6f734e4efcaefd73cdd364aa.json: -------------------------------------------------------------------------------- 1 | {"data":{"slippagePercent":3}} -------------------------------------------------------------------------------- /e2e/numbers.ts: -------------------------------------------------------------------------------- 1 | import BigNumber from 'bignumber.js'; 2 | 3 | export type BigNumberish = number | string | BigNumber; 4 | 5 | export const convertRawAmountToDecimalFormat = ( 6 | value: BigNumberish, 7 | decimals = 18, 8 | ): string => 9 | new BigNumber(value).dividedBy(new BigNumber(10).pow(decimals)).toFixed(); 10 | 11 | export const subtract = ( 12 | numberOne: BigNumberish, 13 | numberTwo: BigNumberish, 14 | ): string => new BigNumber(numberOne).minus(new BigNumber(numberTwo)).toFixed(); 15 | -------------------------------------------------------------------------------- /e2e/parallel/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { UserConfig, mergeConfig } from 'vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | 4 | import viteConfig from '../vitest.config'; 5 | 6 | export default mergeConfig( 7 | viteConfig, 8 | defineConfig({ 9 | test: { 10 | bail: 1, 11 | threads: false, 12 | }, 13 | }) as UserConfig, 14 | ); 15 | -------------------------------------------------------------------------------- /e2e/serial/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { UserConfig, mergeConfig } from 'vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | 4 | import viteConfig from '../vitest.config'; 5 | 6 | export default mergeConfig( 7 | viteConfig, 8 | defineConfig({ 9 | test: { 10 | bail: 1, 11 | threads: false, 12 | sequence: { 13 | shuffle: false, 14 | sequencer: class Sequencer { 15 | sort(files) { 16 | return files; 17 | } 18 | shard(files) { 19 | return files; 20 | } 21 | }, 22 | }, 23 | }, 24 | }) as UserConfig, 25 | ); 26 | -------------------------------------------------------------------------------- /e2e/tokenVariables.ts: -------------------------------------------------------------------------------- 1 | export type TokenNames = 2 | | keyof (typeof tokenAddresses)['mainnet'] 3 | | keyof (typeof tokenAddresses)['optimism']; 4 | 5 | export const tokenAddresses = { 6 | mainnet: { 7 | usdt: '0xdac17f958d2ee523a2206206994597c13d831ec7', 8 | usdc: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 9 | }, 10 | optimism: { 11 | usdt: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', 12 | usdc: '0x0b2c639c533813f4aa9d7837caf62653d097ff85', 13 | }, 14 | }; 15 | 16 | export const tokenNames: Record = { 17 | usdt: 'Tether USD', 18 | usdc: 'USD Coin', 19 | }; 20 | -------------------------------------------------------------------------------- /e2e/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | import { UserConfig } from 'vitest'; 4 | import { defineConfig } from 'vitest/config'; 5 | 6 | export default defineConfig({ 7 | test: { 8 | include: ['./**/**/*.test.ts'], 9 | testTimeout: 120_000, 10 | watch: false, 11 | retry: 2, 12 | bail: 1, 13 | hookTimeout: 30_000, 14 | }, 15 | resolve: { 16 | alias: { 17 | '~': path.resolve(__dirname, '../src'), 18 | }, 19 | }, 20 | }) as UserConfig; 21 | -------------------------------------------------------------------------------- /lavamoat/browserify/background/policy-override.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/background/policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | "browserify>process": { 4 | "globals": { 5 | "clearTimeout": true, 6 | "setTimeout": true 7 | } 8 | }, 9 | "browserify>timers-browserify": { 10 | "globals": { 11 | "clearInterval": true, 12 | "clearTimeout": true, 13 | "setInterval": true, 14 | "setTimeout": true 15 | }, 16 | "packages": { 17 | "browserify>process": true 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /lavamoat/browserify/index.worker.worker/policy-override.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/index.worker.worker/policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/injectProvider/policy-override.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/injectProvider/policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/inpage/policy-override.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/inpage/policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/popup/policy-override.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | } 4 | } -------------------------------------------------------------------------------- /lavamoat/browserify/popup/policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | "browserify>process": { 4 | "globals": { 5 | "clearTimeout": true, 6 | "setTimeout": true 7 | } 8 | }, 9 | "browserify>timers-browserify": { 10 | "globals": { 11 | "clearInterval": true, 12 | "clearTimeout": true, 13 | "setInterval": true, 14 | "setTimeout": true 15 | }, 16 | "packages": { 17 | "browserify>process": true 18 | } 19 | }, 20 | "framer-motion>@emotion/is-prop-valid": { 21 | "packages": { 22 | "framer-motion>@emotion/is-prop-valid>@emotion/memoize": true 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /lavamoat/build-lavamoat/policy-override.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | "browserify": { 4 | "packages": { 5 | "lavamoat-browserify": true 6 | } 7 | }, 8 | "lavamoat-browserify": { 9 | "builtin": { 10 | "fs": true, 11 | "path": true 12 | }, 13 | "packages": { 14 | "lavamoat>lavamoat-core": true, 15 | "lavamoat>json-stable-stringify": true 16 | } 17 | }, 18 | "lavamoat>lavamoat-core": { 19 | "builtin": { 20 | "events": true, 21 | "fs": true, 22 | "path": true 23 | }, 24 | "packages": { 25 | "lavamoat>lavamoat-core>fromentries": true, 26 | "lavamoat>json-stable-stringify": true 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{js,jsx}': ['eslint --fix --cache --max-warnings 0'], 3 | '*.{ts,tsx}': [ 4 | () => 'tsc --skipLibCheck --noEmit ', 5 | "eslint --fix --cache --max-warnings 0 --ignore-pattern '!*.d.ts'", 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /manifest/internal.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Rainbow DEVELOPMENT BUILD", 3 | "description": "THIS EXTENSION IS FOR BETA TESTING" 4 | } -------------------------------------------------------------------------------- /manifest/prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "__MSG_appName__", 3 | "short_name": "__MSG_appShortName__", 4 | "description": "__MSG_appDescription__" 5 | } -------------------------------------------------------------------------------- /scripts/bump.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const { inc, valid } = require('semver'); 3 | 4 | const pkgJson = require('../package.json'); 5 | const manifest = require('../static/manifest.json'); 6 | const currentVersion = valid(pkgJson.version); 7 | const newVersion = inc(currentVersion, 'patch'); 8 | 9 | console.log('bumping from v%s to v%s', currentVersion, newVersion); 10 | 11 | pkgJson.version = newVersion; 12 | 13 | // Update package.json 14 | require('fs').writeFileSync('./package.json', JSON.stringify(pkgJson, null, 2)); 15 | // Update manifest.json 16 | manifest.version = newVersion; 17 | require('fs').writeFileSync( 18 | './static/manifest.json', 19 | JSON.stringify(manifest, null, 2), 20 | ); 21 | 22 | console.log('Done.'); 23 | -------------------------------------------------------------------------------- /scripts/check-lockfile.sh: -------------------------------------------------------------------------------- 1 | git diff yarn.lock 2 | if ! git diff --exit-code yarn.lock; then 3 | echo "Changes were detected in yarn.lock file after running 'yarn setup', which is not expected. Please run 'yarn setup' locally and commit the changes."; 4 | exit 1; 5 | fi -------------------------------------------------------------------------------- /scripts/e2e-parallel-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | MAX_RETRIES=5 3 | RETRY_COUNT=0 4 | 5 | # Function to run tests 6 | run_tests() { 7 | echo "Running Tests..." 8 | yarn vitest e2e/parallel/$1 --config ./e2e/parallel/vitest.config.ts --reporter=verbose --bail 1 9 | } 10 | 11 | # Main loop for retry logic 12 | TEST_RESULT=1 13 | while [ $RETRY_COUNT -lt $MAX_RETRIES ] && [ $TEST_RESULT -ne 0 ]; do 14 | if [ $RETRY_COUNT -gt 0 ]; then 15 | echo "Test failed, attempting retry $RETRY_COUNT..." 16 | fi 17 | 18 | run_tests $1 19 | TEST_RESULT=$? 20 | 21 | RETRY_COUNT=$((RETRY_COUNT+1)) 22 | done 23 | 24 | # Return the result of the tests 25 | exit $TEST_RESULT 26 | -------------------------------------------------------------------------------- /scripts/firefox-manifest.js: -------------------------------------------------------------------------------- 1 | const manifestBase = require('../build/manifest.json'); 2 | const allowList = require('../static/allowlist.json'); 3 | 4 | const manifestFF = { 5 | ...manifestBase, 6 | background: { 7 | "scripts": ["background.js"] 8 | }, 9 | browser_specific_settings: { 10 | "gecko": { 11 | "id": "browserextension@rainbow.me", 12 | "strict_min_version": "115.0" 13 | }, 14 | }, 15 | host_permissions: [ 16 | ...manifestBase.host_permissions, 17 | "", 18 | ] 19 | }; 20 | 21 | require('fs').writeFileSync( 22 | './build/manifest.json', 23 | JSON.stringify(manifestFF, null, 2), 24 | ); -------------------------------------------------------------------------------- /scripts/get-rpc-url.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | NETWORK=$1 3 | KEY=$(grep ALCHEMY_DEV_KEY .env | cut -d '=' -f2) 4 | 5 | case $NETWORK in 6 | "optimism") 7 | echo "https://opt-mainnet.g.alchemy.com/v2/$KEY" 8 | ;; 9 | "mainnet") 10 | echo "https://eth-mainnet.g.alchemy.com/v2/$KEY" 11 | ;; 12 | esac -------------------------------------------------------------------------------- /scripts/unit-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ANVIL_PORT=8545 3 | 4 | # Automatically export all variables 5 | set -a 6 | source .env 7 | set +a 8 | 9 | yarn anvil:kill 10 | yarn anvil > anvil-unit.log 2>&1 & 11 | echo "Launching Anvil..." 12 | 13 | # Give it some time to boot 14 | interval=5 15 | until nc -z localhost $ANVIL_PORT; do 16 | sleep $interval 17 | interval=$((interval * 2)) 18 | done 19 | echo "Anvil Launched..." 20 | 21 | # Run the tests and store the result 22 | echo "Running Tests..." 23 | NODE_OPTIONS='--no-experimental-fetch' vitest 24 | TEST_RESULT=$? 25 | 26 | # kill anvil 27 | echo "Cleaning Up..." 28 | yarn anvil:kill 29 | 30 | # return the result of the tests 31 | exit "$TEST_RESULT" 32 | -------------------------------------------------------------------------------- /src/analytics/flushQueuedEvents.ts: -------------------------------------------------------------------------------- 1 | import { SessionStorage } from '~/core/storage'; 2 | 3 | import { analytics } from '.'; 4 | 5 | export const flushQueuedEvents = async () => { 6 | const queuedEvents = await SessionStorage.get('queuedEvents'); 7 | const events = queuedEvents || []; 8 | for (const event of events) { 9 | analytics.track(event.eventName, event.meta); 10 | } 11 | SessionStorage.set('queuedEvents', []); 12 | }; 13 | -------------------------------------------------------------------------------- /src/analytics/screen.ts: -------------------------------------------------------------------------------- 1 | /* eslint sort-keys: "error"*/ 2 | 3 | import { ROUTES } from '~/entries/popup/urls'; 4 | 5 | /** 6 | * All screen names by path, used by `analytics.screen()`. 7 | * We're flipping the key/value pairs from `ROUTES` to avoid maintenance. 8 | * Route names like `SETTINGS__PRIVACY__WALLETS_AND_KEYS` are 9 | * transformed to `settings.privacy.wallets_and_keys` screen events. 10 | */ 11 | export const screen = Object.fromEntries( 12 | Object.entries(ROUTES).map(([key, value]) => [ 13 | value, 14 | key.toLowerCase().replaceAll('__', '.'), 15 | ]), 16 | ); 17 | -------------------------------------------------------------------------------- /src/analytics/userProperties.ts: -------------------------------------------------------------------------------- 1 | // these can be reported separately so they must be optional 2 | export interface UserProperties { 3 | // number of imported or generated accounts 4 | ownedAccounts?: number; 5 | // number of accounts tied to paired hardware wallets 6 | hardwareAccounts?: number; 7 | // number of watched addresses or ens 8 | watchedAccounts?: number; 9 | // number of imported or generated secret recovery phrases 10 | recoveryPhrases?: number; 11 | // number of imported secret recovery phrases 12 | importedRecoveryPhrases?: number; 13 | // number of unique private keys 14 | privateKeys?: number; 15 | // number of imported unique private keys 16 | importedPrivateKeys?: number; 17 | // number of paired trezor hardware wallets 18 | trezorDevices?: number; 19 | // number of paired ledger hardware wallets 20 | ledgerDevices?: number; 21 | // whether a recovery phrase or private key has been imported 22 | hasImported?: boolean; 23 | } 24 | -------------------------------------------------------------------------------- /src/assets.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-default-export */ 2 | 3 | declare module '*.woff2' { 4 | const path: string; 5 | export default path; 6 | } 7 | 8 | declare module '*.svg'; 9 | declare module '*.png'; 10 | declare module '*.mp3'; 11 | -------------------------------------------------------------------------------- /src/core/graphql/codegen.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const { config } = require('./config'); 3 | 4 | module.exports = { 5 | generates: Object.entries(config).reduce((config, [key, value]) => { 6 | return { 7 | ...config, 8 | [`./__generated__/${key}.ts`]: { 9 | documents: [value.document], 10 | plugins: [ 11 | 'typescript', 12 | 'typescript-operations', 13 | 'typescript-generic-sdk', 14 | ], 15 | schema: [{ [value.schema.url]: { method: value.schema.method } }], 16 | }, 17 | }; 18 | }, {}), 19 | }; 20 | -------------------------------------------------------------------------------- /src/core/graphql/config.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | ens: { 3 | schema: { 4 | url: `https://gateway-arbitrum.network.thegraph.com/api/${process.env.GRAPH_ENS_API_KEY}/subgraphs/id/5XqPmWe6gjyrJtFn9cLy237i4cWw2j9HcUJEXsP5qGtH`, 5 | method: 'POST', 6 | }, 7 | document: './queries/ens.graphql', 8 | }, 9 | metadata: { 10 | schema: { 11 | method: 'GET', 12 | url: 'https://metadata.p.rainbow.me/v1/graph', 13 | }, 14 | document: './queries/metadata.graphql', 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /src/core/graphql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rainbow-me/graphql-client", 3 | "private": true, 4 | "scripts": { 5 | "codegen": "graphql-codegen --config codegen.config.js" 6 | }, 7 | "resolutions": { 8 | "semver": "7.5.2" 9 | }, 10 | "devDependencies": { 11 | "@graphql-codegen/cli": "2.11.7", 12 | "@graphql-codegen/typescript": "2.7.3", 13 | "@graphql-codegen/typescript-generic-sdk": "3.0.1", 14 | "@graphql-codegen/typescript-operations": "2.5.3", 15 | "@graphql-eslint/eslint-plugin": "3.10.7" 16 | } 17 | } -------------------------------------------------------------------------------- /src/core/graphql/queries/ens.graphql: -------------------------------------------------------------------------------- 1 | query getRegistration($id: ID!) { 2 | registration(id: $id) { 3 | id 4 | registrationDate 5 | expiryDate 6 | registrant { 7 | id 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/core/keychain/IKeychain.ts: -------------------------------------------------------------------------------- 1 | import { Signer } from '@ethersproject/abstract-signer'; 2 | import { Mnemonic } from '@ethersproject/hdnode'; 3 | import { Wallet } from '@ethersproject/wallet'; 4 | import { Address } from 'viem'; 5 | 6 | export type PrivateKey = string; 7 | 8 | export type TWallet = Omit & { 9 | address: Address; 10 | privateKey: PrivateKey; 11 | }; 12 | 13 | export interface IKeychain { 14 | type: string; 15 | serialize(): Promise; 16 | deserialize(options: unknown): Promise; 17 | addNewAccount(): Promise>; 18 | addAccountAtIndex(index: number, address: Address): Promise
; 19 | getAccounts(): Promise>; 20 | getSigner(address: Address): Signer; 21 | exportAccount(address: Address): Promise; 22 | exportKeychain(address: Address): Promise; 23 | removeAccount(address: Address): Promise; 24 | } 25 | -------------------------------------------------------------------------------- /src/core/keychain/hdPath.ts: -------------------------------------------------------------------------------- 1 | const DEFAULT_HD_PATH = "m/44'/60'/0'/0"; 2 | const DEFAULT_LEDGER_LIVE_PATH = "m/44'/60'"; 3 | const LEGACY_LEDGER_PATH = "m/44'/60'/0'"; 4 | 5 | export const getHDPathForVendorAndType = ( 6 | index: number, 7 | vendor?: 'Ledger' | 'Trezor', 8 | type?: 'legacy', 9 | ) => { 10 | switch (vendor) { 11 | case 'Ledger': 12 | switch (type) { 13 | case 'legacy': 14 | return `${LEGACY_LEDGER_PATH}/${index}`; 15 | default: 16 | return `${DEFAULT_LEDGER_LIVE_PATH}/${index}'/0/0`; 17 | } 18 | case 'Trezor': 19 | return `${DEFAULT_HD_PATH}/${index}`; 20 | default: 21 | return `${DEFAULT_HD_PATH}/${index}`; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/core/messengers/index.ts: -------------------------------------------------------------------------------- 1 | export type { Messenger } from './internal/createMessenger'; 2 | export { initializeMessenger } from './initializeMessenger'; 3 | -------------------------------------------------------------------------------- /src/core/messengers/internal/isValidReply.ts: -------------------------------------------------------------------------------- 1 | import { ReplyMessage } from './createMessenger'; 2 | 3 | export function isValidReply({ 4 | id, 5 | topic, 6 | message, 7 | }: { 8 | id?: number | string; 9 | topic: string; 10 | message: ReplyMessage; 11 | }) { 12 | if (message.topic !== `< ${topic}`) return; 13 | if (typeof id !== 'undefined' && message.id !== id) return; 14 | if (!message.payload) return; 15 | return true; 16 | } 17 | -------------------------------------------------------------------------------- /src/core/messengers/internal/isValidSend.ts: -------------------------------------------------------------------------------- 1 | import { SendMessage } from './createMessenger'; 2 | 3 | export function isValidSend({ 4 | topic, 5 | message, 6 | }: { 7 | topic: string; 8 | message: SendMessage; 9 | }) { 10 | if (!message.topic) return false; 11 | if (topic !== '*' && message.topic !== `> ${topic}`) return false; 12 | if (topic === '*' && message.topic.startsWith('<')) return false; 13 | return true; 14 | } 15 | -------------------------------------------------------------------------------- /src/core/network/_template.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | import { createWebSocketClient } from './internal/createWebSocketClient'; 3 | 4 | export const exampleHttp = createHttpClient({ 5 | baseUrl: 'https://example.com/api', 6 | // timeout: 10_000, 7 | // headers: { 8 | // 'X-Custom-Header': 'foobar' 9 | // }, 10 | }); 11 | 12 | export const exampleWs = createWebSocketClient({ 13 | baseUrl: 'wss://example.com/ws', 14 | }); 15 | -------------------------------------------------------------------------------- /src/core/network/addys.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | 3 | export const addysHttp = createHttpClient({ 4 | baseUrl: 'https://addys.p.rainbow.me/v3', 5 | headers: { Authorization: `Bearer ${process.env.ADDYS_API_KEY}` as string }, 6 | }); 7 | -------------------------------------------------------------------------------- /src/core/network/aha.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | 3 | export const ahaHttp = createHttpClient({ 4 | baseUrl: 'https://aha.rainbow.me', 5 | }); 6 | -------------------------------------------------------------------------------- /src/core/network/etherscan.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | 3 | export const etherscanHttp = createHttpClient({ 4 | baseUrl: 'https://api.etherscan.io/api', 5 | params: { 6 | apikey: process.env.ETHERSCAN_API_KEY, 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /src/core/network/f2c.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | 3 | const IS_DEV = process.env.IS_DEV === 'true'; 4 | 5 | const STAGING_HOST = `https://f2c.rainbowdotme.workers.dev`; 6 | const PROD_HOST = `https://f2c.rainbow.me`; 7 | 8 | export const f2cHttp = createHttpClient({ 9 | baseUrl: IS_DEV ? STAGING_HOST : PROD_HOST, 10 | }); 11 | -------------------------------------------------------------------------------- /src/core/network/index.ts: -------------------------------------------------------------------------------- 1 | export { etherscanHttp } from './etherscan'; 2 | export { f2cHttp } from './f2c'; 3 | export { meteorologyHttp } from './meteorology'; 4 | export { 5 | refractionAssetsMessages, 6 | refractionAssetsWs, 7 | } from './refractionAssetsWs'; 8 | -------------------------------------------------------------------------------- /src/core/network/internal/createHttpClient.ts: -------------------------------------------------------------------------------- 1 | import { RainbowFetchClient, RainbowFetchRequestOpts } from './rainbowFetch'; 2 | 3 | export function createHttpClient({ 4 | baseUrl, 5 | headers, 6 | params, 7 | timeout, 8 | }: { 9 | baseUrl: string; 10 | } & RainbowFetchRequestOpts) { 11 | return new RainbowFetchClient({ baseUrl, headers, params, timeout }); 12 | } 13 | -------------------------------------------------------------------------------- /src/core/network/internal/createWebSocketClient.ts: -------------------------------------------------------------------------------- 1 | import { ManagerOptions, io } from 'socket.io-client'; 2 | 3 | export function createWebSocketClient({ 4 | baseUrl, 5 | query, 6 | }: { 7 | baseUrl: string; 8 | query?: ManagerOptions['query']; 9 | }) { 10 | return io(baseUrl, { 11 | query, 12 | transports: ['websocket'], 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /src/core/network/meteorology.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | 3 | export const meteorologyHttp = createHttpClient({ 4 | baseUrl: 'https://metadata.p.rainbow.me/meteorology/v1/gas', 5 | params: {}, 6 | }); 7 | -------------------------------------------------------------------------------- /src/core/network/nftAllowList.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | 3 | export const nftAllowListClient = createHttpClient({ 4 | baseUrl: 'https://metadata.p.rainbow.me/token-list', 5 | }); 6 | -------------------------------------------------------------------------------- /src/core/network/refractionAssetsWs.ts: -------------------------------------------------------------------------------- 1 | import { createWebSocketClient } from './internal/createWebSocketClient'; 2 | 3 | export const refractionAssetsMessages = { 4 | ASSET_INFO: { 5 | RECEIVED: 'received assets info', 6 | }, 7 | ASSETS: { 8 | CHANGED: 'changed assets prices', 9 | RECEIVED: 'received assets prices', 10 | }, 11 | CONNECT: 'connect', 12 | DISCONNECT: 'disconnect', 13 | ERROR: 'error', 14 | MAINNET_ASSET_DISCOVERY: 'received address mainnet-assets-discovery', 15 | RECONNECT_ATTEMPT: 'reconnect_attempt', 16 | }; 17 | 18 | export const refractionAssetsWs = createWebSocketClient({ 19 | baseUrl: `${process.env.DATA_ENDPOINT}/assets`, 20 | query: { 21 | api_token: process.env.DATA_API_KEY, 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /src/core/network/tokenSearch.ts: -------------------------------------------------------------------------------- 1 | import { createHttpClient } from './internal/createHttpClient'; 2 | 3 | export const tokenSearchHttp = createHttpClient({ 4 | baseUrl: 'https://token-search.rainbow.me/v3/tokens', 5 | params: {}, 6 | }); 7 | -------------------------------------------------------------------------------- /src/core/raps/actions/index.ts: -------------------------------------------------------------------------------- 1 | export { estimateSwapGasLimit, executeSwap, swap } from './swap'; 2 | export { claim } from './claim'; 3 | export { 4 | assetNeedsUnlocking, 5 | estimateApprove, 6 | executeApprove, 7 | unlock, 8 | } from './unlock'; 9 | -------------------------------------------------------------------------------- /src/core/raps/common.ts: -------------------------------------------------------------------------------- 1 | import { RapAction, RapActionParameterMap, RapActionTypes } from './references'; 2 | 3 | export function createNewAction( 4 | type: T, 5 | parameters: RapActionParameterMap[T], 6 | ): RapAction { 7 | const newAction = { 8 | parameters, 9 | transaction: { confirmed: null, hash: null }, 10 | type, 11 | }; 12 | return newAction; 13 | } 14 | 15 | export function createNewRap( 16 | actions: RapAction[], 17 | ) { 18 | return { 19 | actions, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/core/react-query/createQueryKey.ts: -------------------------------------------------------------------------------- 1 | export function createQueryKey( 2 | /** A categorial key for the query. */ 3 | key: string, 4 | 5 | /** Arguments to pass onto the query function. 6 | * Note: these arguments are also used to generate the query key, 7 | * meaning that data will be cached against these args. 8 | */ 9 | args: TArgs, 10 | 11 | /** Configuration for the query key. */ 12 | config: { 13 | /** 14 | * A persister version number for the query. 15 | * If a persisterVersion exists, this means that this query 16 | * will be stored in AsyncStorage. 17 | * When a query is stored against a persisterVersion, 18 | * and is later changed, the cache will bust for this query, 19 | * and it will be invalidated. 20 | */ 21 | persisterVersion?: number; 22 | } = {}, 23 | ) { 24 | return [args, key, config] as const; 25 | } 26 | -------------------------------------------------------------------------------- /src/core/react-query/index.ts: -------------------------------------------------------------------------------- 1 | export { createQueryKey } from './createQueryKey'; 2 | 3 | export { persistOptions, queryClient } from './queryClient'; 4 | 5 | export type { 6 | MutationConfig, 7 | MutationFunctionResult, 8 | InfiniteQueryConfig, 9 | QueryConfig, 10 | QueryFunctionArgs, 11 | QueryFunctionResult, 12 | } from './types'; 13 | -------------------------------------------------------------------------------- /src/core/references/ethUnits.ts: -------------------------------------------------------------------------------- 1 | export const ethUnits = { 2 | noether: 0, 3 | wei: 1, 4 | kwei: 1000, 5 | Kwei: 1000, 6 | babbage: 1000, 7 | femtoether: 1000, 8 | mwei: 1000000, 9 | Mwei: 1000000, 10 | lovelace: 1000000, 11 | picoether: 1000000, 12 | gwei: 1000000000, 13 | Gwei: 1000000000, 14 | shannon: 1000000000, 15 | nanoether: 1000000000, 16 | nano: 1000000000, 17 | szabo: 1000000000000, 18 | microether: 1000000000000, 19 | micro: 1000000000000, 20 | finney: 1000000000000000, 21 | milliether: 1000000000000000, 22 | milli: 1000000000000000, 23 | ether: 1000000000000000000, 24 | kether: 1000000000000000000000, 25 | grand: 1000000000000000000000, 26 | mether: 1000000000000000000000000, 27 | gether: 1000000000000000000000000000, 28 | tether: 1000000000000000000000000000000, 29 | }; 30 | -------------------------------------------------------------------------------- /src/core/references/links.ts: -------------------------------------------------------------------------------- 1 | export const RAINBOW_LEARN_URL = 'https://learn.rainbow.me'; 2 | export const RAINBOW_TWITTER_URL = 'https:/twitter.com/rainbowdotme'; 3 | export const RAINBOW_SUPPORT_URL = 'https://rainbow.me/extension/support'; 4 | export const RAINBOW_FEEDBACK_URL = 'https://rainbow.me/extension/feedback'; 5 | export const RAINBOW_WAITLIST_URL = 'https://rainbow.me/waitlist'; 6 | export const RAINBOW_TEST_DAPP = 'https://bx-test-dapp.vercel.app'; 7 | -------------------------------------------------------------------------------- /src/core/references/themes.ts: -------------------------------------------------------------------------------- 1 | import { i18n } from '../languages'; 2 | import { ThemeData, ThemeOption } from '../types/settings'; 3 | 4 | export const themeOptions: { [key in ThemeOption]: ThemeData } = { 5 | system: { 6 | symbol: 'gear', 7 | label: i18n.t('settings.theme.system'), 8 | color: 'labelTertiary', 9 | }, 10 | light: { 11 | symbol: 'sun.max', 12 | label: i18n.t('settings.theme.light'), 13 | color: 'yellow', 14 | }, 15 | dark: { 16 | symbol: 'moon', 17 | label: i18n.t('settings.theme.dark'), 18 | color: 'purple', 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /src/core/references/txSpeed.ts: -------------------------------------------------------------------------------- 1 | import { GasSpeed } from '../types/gas'; 2 | 3 | export const txSpeedEmoji = { 4 | [GasSpeed.CUSTOM]: '⚙️', 5 | [GasSpeed.NORMAL]: '⏱', 6 | [GasSpeed.FAST]: '🚀', 7 | [GasSpeed.URGENT]: '🚨', 8 | }; 9 | -------------------------------------------------------------------------------- /src/core/resources/_selectors/index.ts: -------------------------------------------------------------------------------- 1 | export { selectUserAssetWithUniqueId, selectUserAssetsList } from './assets'; 2 | export { selectTransactionsByDate } from './transactions'; 3 | -------------------------------------------------------------------------------- /src/core/resources/_selectors/transactions.ts: -------------------------------------------------------------------------------- 1 | import { groupBy } from 'lodash'; 2 | 3 | import { RainbowTransaction } from '~/core/types/transactions'; 4 | import { groupTransactionByDate } from '~/core/utils/dates'; 5 | 6 | export const selectTransactionsByDate = ( 7 | transactions: RainbowTransaction[], 8 | ) => { 9 | const sortedTransactions = transactions.sort((tx1, tx2) => { 10 | if (tx1.status === 'pending' && tx2.status === 'pending') 11 | return (tx2.nonce || 0) - (tx1.nonce || 0); 12 | 13 | if (tx1.status === 'pending') return -1; 14 | if (tx2.status === 'pending') return 1; 15 | if (!tx1.minedAt) return -1; 16 | if (!tx2.minedAt) return 1; 17 | 18 | return (tx2.minedAt || 0) - (tx1.minedAt || 0); 19 | }); 20 | return groupBy(sortedTransactions, groupTransactionByDate); 21 | }; 22 | -------------------------------------------------------------------------------- /src/core/resources/assets/index.ts: -------------------------------------------------------------------------------- 1 | export { useAssets } from './assets'; 2 | export { useUserAssets, useUserAssetsByChain } from './userAssets'; 3 | export type { UserAssetsArgs, UserAssetsByChainArgs } from './userAssets'; 4 | -------------------------------------------------------------------------------- /src/core/resources/ens/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/core/resources/ens/index.ts -------------------------------------------------------------------------------- /src/core/resources/f2c/index.ts: -------------------------------------------------------------------------------- 1 | export { useProvidersList } from './providers'; 2 | export { fetchProviderWidgetUrl } from './widgetUrl'; 3 | -------------------------------------------------------------------------------- /src/core/resources/gas/index.ts: -------------------------------------------------------------------------------- 1 | export { fetchMeteorology, useMeteorology } from './meteorology'; 2 | export { getProviderGas, useProviderGas } from './providerGas'; 3 | export { useGasData } from './gasData'; 4 | export { useEstimateGasLimit } from './estimateGasLimit'; 5 | -------------------------------------------------------------------------------- /src/core/resources/nfts/index.ts: -------------------------------------------------------------------------------- 1 | export { useNftCollections } from './collections'; 2 | export { useGalleryNfts } from './galleryNfts'; 3 | export { useNftsForCollection } from './nftsForCollection'; 4 | -------------------------------------------------------------------------------- /src/core/resources/search/index.ts: -------------------------------------------------------------------------------- 1 | export { useTokenSearch } from './tokenSearch'; 2 | -------------------------------------------------------------------------------- /src/core/resources/search/parseTokenSearch.ts: -------------------------------------------------------------------------------- 1 | import { AddressOrEth } from '~/core/types/assets'; 2 | import { ChainId } from '~/core/types/chains'; 3 | import { SearchAsset } from '~/core/types/search'; 4 | import { isNativeAsset } from '~/core/utils/chains'; 5 | 6 | export function parseTokenSearch( 7 | asset: SearchAsset, 8 | chainId: ChainId, 9 | ): SearchAsset { 10 | const networkInfo = asset.networks[chainId]; 11 | const mainnetInfo = asset.networks[ChainId.mainnet]; 12 | 13 | return { 14 | ...asset, 15 | address: networkInfo ? networkInfo.address : asset.address, 16 | chainId, 17 | decimals: networkInfo ? networkInfo.decimals : asset.decimals, 18 | isNativeAsset: isNativeAsset(asset.address, chainId), 19 | mainnetAddress: mainnetInfo?.address as AddressOrEth, 20 | uniqueId: `${networkInfo?.address || asset.uniqueId}_${chainId}`, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/core/resources/transactions/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | fetchFirstTransactionTimestamp, 3 | useFirstTransactionTimestamp, 4 | } from './firstTransactionTimestampQuery'; 5 | export type { FirstTransactionTimestampArgs } from './firstTransactionTimestampQuery'; 6 | -------------------------------------------------------------------------------- /src/core/state/currentHomeSheet/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '../internal/createRainbowStore'; 2 | 3 | type SheetMode = 'cancel' | 'none' | 'speedUp'; 4 | 5 | export interface CurrentSheetState { 6 | getCurrentHomeSheet: () => SheetMode | null; 7 | setCurrentHomeSheet: (sheetMode: SheetMode) => void; 8 | sheet: SheetMode; 9 | } 10 | 11 | export const useCurrentHomeSheetStore = createRainbowStore( 12 | (set, get) => ({ 13 | getCurrentHomeSheet: () => get().sheet, 14 | setCurrentHomeSheet: (sheetMode: SheetMode) => set({ sheet: sheetMode }), 15 | sheet: 'none', 16 | }), 17 | ); 18 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/analyticsDisabled.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | import { getBrowser } from '~/entries/popup/hooks/useBrowser'; 3 | 4 | export interface AnalyticsDisabledState { 5 | analyticsDisabled: boolean; 6 | setAnalyticsDisabled: (analyticsDisabled: boolean) => void; 7 | } 8 | 9 | export const useAnalyticsDisabledStore = 10 | createRainbowStore( 11 | (set) => ({ 12 | analyticsDisabled: getBrowser() === 'Firefox', 13 | setAnalyticsDisabled: (newanalyticsDisabled) => 14 | set({ analyticsDisabled: newanalyticsDisabled }), 15 | }), 16 | { 17 | storageKey: 'analyticsDisabled', 18 | version: 1, 19 | }, 20 | ); 21 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/autoLockTimer.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | import { AutoLockTimerOption } from '~/core/types/settings'; 3 | 4 | export interface AutoLockTimerState { 5 | autoLockTimer: AutoLockTimerOption; 6 | setAutoLockTimer: (autoLockTimer: AutoLockTimerOption) => void; 7 | } 8 | 9 | export const useAutoLockTimerStore = createRainbowStore( 10 | (set) => ({ 11 | autoLockTimer: 'none', 12 | setAutoLockTimer: (newAutoLockTimer) => 13 | set({ autoLockTimer: newAutoLockTimer }), 14 | }), 15 | { 16 | storageKey: 'autoLockTimer', 17 | version: 0, 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/connectedToHardhat.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '../internal/createRainbowStore'; 2 | 3 | export interface ConnectedToHardhatState { 4 | connectedToHardhat: boolean; 5 | setConnectedToHardhat: (connectedToHardhat: boolean) => void; 6 | 7 | connectedToHardhatOp: boolean; 8 | setConnectedToHardhatOp: (connectedToHardhatOp: boolean) => void; 9 | } 10 | 11 | export const useConnectedToHardhatStore = 12 | createRainbowStore( 13 | (set) => ({ 14 | connectedToHardhat: false, 15 | setConnectedToHardhat: (connectedToHardhat) => { 16 | set({ connectedToHardhat }); 17 | }, 18 | 19 | connectedToHardhatOp: false, 20 | setConnectedToHardhatOp: (connectedToHardhatOp) => { 21 | set({ connectedToHardhatOp }); 22 | }, 23 | }), 24 | { 25 | storageKey: 'connectedToHardhat', 26 | version: 0, 27 | }, 28 | ); 29 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/currentChainId.ts: -------------------------------------------------------------------------------- 1 | import { ChainId } from '~/core/types/chains'; 2 | 3 | import { createRainbowStore } from '../internal/createRainbowStore'; 4 | 5 | export interface CurrentChainIdState { 6 | currentChainId: number; 7 | setCurrentChainId: (chainId: number) => void; 8 | } 9 | 10 | export const useCurrentChainIdStore = createRainbowStore( 11 | (set) => ({ 12 | currentChainId: ChainId.mainnet, 13 | setCurrentChainId: (newChainId) => set({ currentChainId: newChainId }), 14 | }), 15 | { 16 | storageKey: 'currentChainId', 17 | version: 0, 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/currentCurrency.ts: -------------------------------------------------------------------------------- 1 | import { SupportedCurrencyKey } from '~/core/references'; 2 | 3 | import { createRainbowStore } from '../internal/createRainbowStore'; 4 | 5 | export interface CurrentCurrencyState { 6 | currentCurrency: SupportedCurrencyKey; 7 | setCurrentCurrency: (currency: SupportedCurrencyKey) => void; 8 | } 9 | 10 | export const useCurrentCurrencyStore = createRainbowStore( 11 | (set) => ({ 12 | currentCurrency: 'USD', 13 | setCurrentCurrency: (newCurrency) => set({ currentCurrency: newCurrency }), 14 | }), 15 | { 16 | storageKey: 'currentCurrency', 17 | version: 0, 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/defaultTxSpeed.ts: -------------------------------------------------------------------------------- 1 | import { GasSpeed } from '~/core/types/gas'; 2 | import { DefaultTxSpeedOption } from '~/core/types/settings'; 3 | 4 | import { createRainbowStore } from '../internal/createRainbowStore'; 5 | 6 | export interface DefaultTxSpeedState { 7 | defaultTxSpeed: DefaultTxSpeedOption; 8 | setDefaultTxSpeed: (defaultTxSpeed: DefaultTxSpeedOption) => void; 9 | } 10 | 11 | export const useDefaultTxSpeedStore = createRainbowStore( 12 | (set) => ({ 13 | defaultTxSpeed: GasSpeed.NORMAL, 14 | setDefaultTxSpeed: (newDefaultTxSpeed) => 15 | set({ defaultTxSpeed: newDefaultTxSpeed }), 16 | }), 17 | { 18 | storageKey: 'defaultTxSpeed', 19 | version: 0, 20 | }, 21 | ); 22 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/developerToolsEnabled.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | export interface DeveloperToolsEnabledState { 4 | developerToolsEnabled: boolean; 5 | setDeveloperToolsEnabled: (developerToolsEnabled: boolean) => void; 6 | } 7 | 8 | export const useDeveloperToolsEnabledStore = 9 | createRainbowStore( 10 | (set) => ({ 11 | developerToolsEnabled: false, 12 | setDeveloperToolsEnabled: (developerToolsEnabled) => 13 | set({ developerToolsEnabled }), 14 | }), 15 | { 16 | storageKey: 'developerTools', 17 | version: 0, 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/hideAssetBalances.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '../internal/createRainbowStore'; 2 | 3 | export interface HideAssetBalancesState { 4 | hideAssetBalances: boolean; 5 | setHideAssetBalances: (hideAssetBalances: boolean) => void; 6 | } 7 | 8 | export const useHideAssetBalancesStore = 9 | createRainbowStore( 10 | (set) => ({ 11 | hideAssetBalances: false, 12 | setHideAssetBalances: (newHideAssetBalances) => 13 | set({ hideAssetBalances: newHideAssetBalances }), 14 | }), 15 | { 16 | storageKey: 'hideAssetBalances', 17 | version: 0, 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/hideSmallBalances.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | export interface HideSmallBalancesState { 4 | hideSmallBalances: boolean; 5 | setHideSmallBalances: (hideSmallBalances: boolean) => void; 6 | } 7 | 8 | export const useHideSmallBalancesStore = 9 | createRainbowStore( 10 | (set) => ({ 11 | hideSmallBalances: false, 12 | setHideSmallBalances: (newHideSmallBalances) => 13 | set({ hideSmallBalances: newHideSmallBalances }), 14 | }), 15 | { 16 | storageKey: 'hideSmallBalances', 17 | version: 0, 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/index.ts: -------------------------------------------------------------------------------- 1 | export { useCurrentAddressStore } from './currentAddress'; 2 | export { useCurrentChainIdStore } from './currentChainId'; 3 | export { useCurrentCurrencyStore } from './currentCurrency'; 4 | export { useCurrentLanguageStore } from './currentLanguage'; 5 | export { useCurrentThemeStore } from './currentTheme'; 6 | export { useIsDefaultWalletStore } from './isDefaultWallet'; 7 | export { useTabNavigation } from './tabNavigation'; 8 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/isDefaultWallet.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | export interface IsDefaultWalletState { 4 | isDefaultWallet: boolean; 5 | setIsDefaultWallet: (isDefaultWallet: boolean) => void; 6 | } 7 | 8 | export const useIsDefaultWalletStore = createRainbowStore( 9 | (set) => ({ 10 | isDefaultWallet: true, 11 | setIsDefaultWallet: (newIsDefaultWallet) => 12 | set({ isDefaultWallet: newIsDefaultWallet }), 13 | }), 14 | { 15 | storageKey: 'isDefaultWallet', 16 | version: 0, 17 | }, 18 | ); 19 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/tabNavigation.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | import { Tab } from '~/entries/popup/components/Tabs/TabBar'; 3 | 4 | interface TabNavigationState { 5 | selectedTab: Tab; 6 | setSelectedTab: (newSelectedTab: Tab) => void; 7 | } 8 | 9 | export const useTabNavigation = createRainbowStore( 10 | (set) => ({ 11 | selectedTab: 'tokens', 12 | setSelectedTab: (newSelectedTab) => set({ selectedTab: newSelectedTab }), 13 | }), 14 | { 15 | storageKey: 'tabNavigation', 16 | version: 0, 17 | }, 18 | ); 19 | -------------------------------------------------------------------------------- /src/core/state/currentSettings/testnetMode.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | export interface TestnetModeState { 4 | testnetMode: boolean; 5 | setTestnetMode: (testnetMode: boolean) => void; 6 | } 7 | 8 | export const useTestnetModeStore = createRainbowStore( 9 | (set) => ({ 10 | testnetMode: false, 11 | setTestnetMode: (testnetMode) => set({ testnetMode }), 12 | }), 13 | { 14 | storageKey: 'testnetMode', 15 | version: 0, 16 | }, 17 | ); 18 | -------------------------------------------------------------------------------- /src/core/state/degenMode/index.ts: -------------------------------------------------------------------------------- 1 | import { analytics } from '~/analytics'; 2 | import { event } from '~/analytics/event'; 3 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 4 | 5 | export const useDegenMode = createRainbowStore( 6 | () => ({ 7 | isDegenModeEnabled: false, 8 | }), 9 | { 10 | storageKey: 'degenMode', 11 | version: 1, 12 | }, 13 | ); 14 | 15 | export const toggleDegenMode = () => 16 | useDegenMode.setState((s) => { 17 | analytics.track(event.toggledDegenMode, { 18 | enabled: !s.isDegenModeEnabled, 19 | }); 20 | return { isDegenModeEnabled: !s.isDegenModeEnabled }; 21 | }); 22 | -------------------------------------------------------------------------------- /src/core/state/deviceId/index.ts: -------------------------------------------------------------------------------- 1 | import { uuid4 } from '@sentry/utils'; 2 | 3 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 4 | 5 | export interface DeviceIdStore { 6 | deviceId: string; 7 | setDeviceId: (deviceId: string) => void; 8 | } 9 | 10 | export const useDeviceIdStore = createRainbowStore( 11 | (set) => ({ 12 | deviceId: uuid4(), 13 | setDeviceId: (newDeviceId) => set({ deviceId: newDeviceId }), 14 | }), 15 | { 16 | storageKey: 'deviceId', 17 | version: 0, 18 | }, 19 | ); 20 | -------------------------------------------------------------------------------- /src/core/state/dominantColor/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | type ColorCacheStore = { 4 | colorCache: Record; 5 | setColorCache: (imageUrl: string, color: string | null) => void; 6 | }; 7 | 8 | export const useColorCacheStore = createRainbowStore( 9 | (set) => ({ 10 | colorCache: {}, 11 | setColorCache: (imageUrl, color) => 12 | set((state) => ({ 13 | colorCache: { ...state.colorCache, [imageUrl]: color }, 14 | })), 15 | }), 16 | { 17 | storageKey: 'dominantColorStore', 18 | version: 0, 19 | }, 20 | ); 21 | -------------------------------------------------------------------------------- /src/core/state/error/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | export interface ErrorState { 4 | error: Error | null; 5 | setError: (e: Error | null) => void; 6 | } 7 | 8 | export const useErrorStore = createRainbowStore((set) => ({ 9 | error: null, 10 | setError: (error) => set({ error }), 11 | })); 12 | -------------------------------------------------------------------------------- /src/core/state/homePromptsQueue/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | type HomePrompt = 'app-connection' | 'wallet-backup'; 4 | export interface HomePromptsQueue { 5 | queue: HomePrompt[]; 6 | popQueue: () => void; 7 | } 8 | 9 | export const useHomePromptsQueueStore = createRainbowStore( 10 | (set, get) => ({ 11 | queue: ['wallet-backup', 'app-connection'], 12 | popQueue: () => { 13 | const { queue } = get(); 14 | queue.splice(0, 1); 15 | set({ queue: [...queue] }); 16 | }, 17 | }), 18 | ); 19 | -------------------------------------------------------------------------------- /src/core/state/internal/persistStorage.ts: -------------------------------------------------------------------------------- 1 | import { StateStorage } from 'zustand/middleware'; 2 | 3 | import { LocalStorage } from '~/core/storage'; 4 | 5 | export const persistStorage: StateStorage = { 6 | getItem: async (key: string): Promise => { 7 | return (await LocalStorage.get(key)) || null; 8 | }, 9 | setItem: async (key: string, value: string): Promise => { 10 | await LocalStorage.set(key, value); 11 | }, 12 | removeItem: async (key: string): Promise => { 13 | await LocalStorage.remove(key); 14 | }, 15 | }; 16 | 17 | export const noopStorage: StateStorage = { 18 | getItem: async (): Promise => null, 19 | setItem: async (): Promise => undefined, 20 | removeItem: async (): Promise => undefined, 21 | }; 22 | -------------------------------------------------------------------------------- /src/core/state/networks/__tests__/data/userChainsOrder.mock.ts: -------------------------------------------------------------------------------- 1 | import { UserChainsState } from '~/core/state/userChains'; 2 | export const GRANT_DATA: UserChainsState['userChainsOrder'] = [ 3 | 1, 10, 56, 137, 8453, 33139, 42161, 43114, 81457, 7777777, 666666666, 130, 4 | 33111, 57073, 763373, 8453, 8333, 1996, 1992, 1625, 13505, 5 | ]; 6 | export const MIKE_DATA: UserChainsState['userChainsOrder'] = [ 7 | 1, 10, 56, 137, 8453, 33139, 42161, 43114, 81457, 7777777, 666666666, 534352, 8 | 666666666, 1, 324, 130, 7777777, 59144, 5112, 1625, 1625, 1625, 33111, 57073, 9 | 763373, 11155111, 2020, 42161, 8333, 80094, 80085, 80084, 80084, 1996, 1992, 10 | 13505, 11 | ]; 12 | export const DANIEL_DATA: UserChainsState['userChainsOrder'] = [ 13 | 1, 8453, 10, 137, 666666666, 42161, 56, 33139, 43114, 81457, 7777777, 1996, 14 | 80094, 534352, 33111, 57073, 763373, 1625, 80084, 314, 1, 999, 15 | ]; 16 | -------------------------------------------------------------------------------- /src/core/state/networks/constants.ts: -------------------------------------------------------------------------------- 1 | import buildTimeNetworks from 'static/data/networks.json'; 2 | 3 | export const DEFAULT_PRIVATE_MEMPOOL_TIMEOUT = 2 * 60 * 1_000; // 2 minutes 4 | 5 | export const RPC_PROXY_API_KEY = process.env.RPC_PROXY_API_KEY; 6 | export const INTERNAL_BUILD = process.env.INTERNAL_BUILD === 'true'; 7 | export const IS_DEV = process.env.IS_DEV === 'true'; 8 | export const IS_TESTING = process.env.IS_TESTING === 'true'; 9 | 10 | export { buildTimeNetworks }; 11 | -------------------------------------------------------------------------------- /src/core/state/networks/types.ts: -------------------------------------------------------------------------------- 1 | import { ChainPreferences, Networks } from '~/core/types/chains'; 2 | 3 | // Network state interface 4 | export interface NetworkState { 5 | networks: Networks; // contains backend-driven networks and backend-driven custom networks 6 | userPreferences: Record; // contains user-driven overrides for backend-driven networks AND user added custom networks 7 | chainOrder: Array; 8 | enabledChainIds: Set; 9 | } 10 | 11 | // Migration state type 12 | export type NetworksStoreMigrationState = { 13 | didCompleteNetworksMigration: boolean; 14 | }; 15 | -------------------------------------------------------------------------------- /src/core/state/savedEnsNames/index.ts: -------------------------------------------------------------------------------- 1 | import { Address } from 'viem'; 2 | 3 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 4 | 5 | type SavedNamesStore = { 6 | savedNames: Record; 7 | save: (name: string, address: Address) => void; 8 | }; 9 | 10 | export const useSavedEnsNamesStore = createRainbowStore( 11 | (set, get) => ({ 12 | savedNames: {}, 13 | save(name, address) { 14 | const savedNames = get().savedNames; 15 | savedNames[address] = name; 16 | set({ savedNames }); 17 | }, 18 | }), 19 | { storageKey: 'ensSavedNames', version: 0 }, 20 | ); 21 | -------------------------------------------------------------------------------- /src/core/state/selectedNft/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | import { UniqueAsset } from '~/core/types/nfts'; 3 | 4 | export interface SelectedNftState { 5 | setSelectedNft: (nft?: UniqueAsset) => void; 6 | selectedNft: UniqueAsset | null; 7 | } 8 | 9 | export const useSelectedNftStore = createRainbowStore( 10 | (set) => ({ 11 | setSelectedNft: (selectedNft?: UniqueAsset) => { 12 | set({ selectedNft }); 13 | }, 14 | selectedNft: null, 15 | }), 16 | ); 17 | -------------------------------------------------------------------------------- /src/core/state/selectedToken/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | import { ParsedUserAsset } from '~/core/types/assets'; 3 | 4 | export interface SelectedTokenState { 5 | getSelectedToken: () => ParsedUserAsset | null; 6 | setSelectedToken: (token?: ParsedUserAsset) => void; 7 | selectedToken: ParsedUserAsset | null; 8 | } 9 | 10 | export const useSelectedTokenStore = createRainbowStore( 11 | (set, get) => ({ 12 | getSelectedToken: () => get()?.selectedToken, 13 | setSelectedToken: (selectedToken?: ParsedUserAsset) => { 14 | set({ selectedToken }); 15 | }, 16 | selectedToken: null, 17 | }), 18 | ); 19 | -------------------------------------------------------------------------------- /src/core/state/selectedTransaction/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | import { RainbowTransaction } from '~/core/types/transactions'; 3 | 4 | export interface SelectedTransactionState { 5 | getSelectedTransaction: () => RainbowTransaction | null; 6 | setSelectedTransaction: (transaction?: RainbowTransaction) => void; 7 | selectedTransaction: RainbowTransaction | null; 8 | } 9 | 10 | export const useSelectedTransactionStore = 11 | createRainbowStore((set, get) => ({ 12 | getSelectedTransaction: () => get()?.selectedTransaction, 13 | setSelectedTransaction: (selectedTransaction?: RainbowTransaction) => { 14 | set({ selectedTransaction }); 15 | }, 16 | selectedTransaction: null, 17 | })); 18 | -------------------------------------------------------------------------------- /src/core/state/sound/index.ts: -------------------------------------------------------------------------------- 1 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 2 | 3 | export interface SoundState { 4 | soundsEnabled: boolean; 5 | toggleSoundsEnabled: (enabled: boolean) => void; 6 | } 7 | 8 | export const useSoundStore = createRainbowStore( 9 | (set) => ({ 10 | soundsEnabled: true, 11 | toggleSoundsEnabled: (soundsEnabled) => set({ soundsEnabled }), 12 | }), 13 | { 14 | storageKey: 'sound', 15 | version: 0, 16 | }, 17 | ); 18 | -------------------------------------------------------------------------------- /src/core/state/walletOrder/index.ts: -------------------------------------------------------------------------------- 1 | import { Address } from 'viem'; 2 | 3 | import { createRainbowStore } from '~/core/state/internal/createRainbowStore'; 4 | 5 | export interface WalletOrderStore { 6 | walletOrder: Address[]; 7 | saveWalletOrder: (newWalletOrder: Address[]) => void; 8 | deleteWalletOrder: ({ removedAddress }: { removedAddress: Address }) => void; 9 | } 10 | 11 | export const useWalletOrderStore = createRainbowStore( 12 | (set, get) => ({ 13 | walletOrder: [], 14 | saveWalletOrder: (newWalletOrder) => { 15 | set({ walletOrder: newWalletOrder }); 16 | }, 17 | deleteWalletOrder: ({ removedAddress }) => { 18 | const walletOrder = get().walletOrder; 19 | const newWalletOrder = walletOrder.filter( 20 | (addr) => addr !== removedAddress, 21 | ); 22 | set({ walletOrder: newWalletOrder }); 23 | }, 24 | }), 25 | { 26 | storageKey: 'walletOrder', 27 | version: 0, 28 | }, 29 | ); 30 | -------------------------------------------------------------------------------- /src/core/transports/index.ts: -------------------------------------------------------------------------------- 1 | export { providerRequestTransport } from './providerRequestTransport'; 2 | -------------------------------------------------------------------------------- /src/core/types/keychainTypes.ts: -------------------------------------------------------------------------------- 1 | export enum KeychainType { 2 | HdKeychain = 'HdKeychain', 3 | KeyPairKeychain = 'KeyPairKeychain', 4 | ReadOnlyKeychain = 'ReadOnlyKeychain', 5 | HardwareWalletKeychain = 'HardwareWalletKeychain', 6 | } 7 | 8 | export type KeychainWallet = { 9 | type: KeychainType; 10 | accounts: `0x${string}`[]; 11 | imported: boolean; 12 | vendor?: 'Ledger' | 'Trezor'; 13 | }; 14 | -------------------------------------------------------------------------------- /src/core/types/settings.ts: -------------------------------------------------------------------------------- 1 | import { TextStyles } from '~/design-system/styles/core.css'; 2 | import { SymbolName } from '~/design-system/styles/designTokens'; 3 | 4 | import { GasSpeed } from './gas'; 5 | 6 | export type AutoLockTimerOption = 7 | | 'immediately' 8 | | 'one_minute' 9 | | 'five_minutes' 10 | | 'ten_minutes' 11 | | 'fifteen_minutes' 12 | | 'thirty_minutes' 13 | | 'one_hour' 14 | | 'twelve_hours' 15 | | 'twenty_four_hours' 16 | | 'none'; 17 | 18 | export interface AutoLockTimerData { 19 | label: string; 20 | mins: number | null; 21 | } 22 | 23 | export type DefaultTxSpeedOption = 24 | | GasSpeed.NORMAL 25 | | GasSpeed.FAST 26 | | GasSpeed.URGENT; 27 | 28 | export type ThemeOption = 'light' | 'dark' | 'system'; 29 | 30 | export interface ThemeData { 31 | symbol: SymbolName; 32 | label: string; 33 | color: TextStyles['color']; 34 | } 35 | -------------------------------------------------------------------------------- /src/core/types/walletTypes.ts: -------------------------------------------------------------------------------- 1 | export enum EthereumWalletType { 2 | mnemonic = 'mnemonic', 3 | privateKey = 'privateKey', 4 | readOnly = 'readOnly', 5 | seed = 'seed', 6 | ledgerPublicKey = 'ledgerPublicKey', 7 | trezorPublicKey = 'trezorPublicKey', 8 | } 9 | -------------------------------------------------------------------------------- /src/core/utils/address.ts: -------------------------------------------------------------------------------- 1 | import { Address } from 'viem'; 2 | 3 | import { AddressOrEth, UniqueId } from '../types/assets'; 4 | import { ChainId } from '../types/chains'; 5 | 6 | export function truncateAddress(address?: AddressOrEth) { 7 | if (!address) return ''; 8 | return `${address?.slice(0, 6)}…${address?.slice(-4)}`; 9 | } 10 | 11 | export function deriveAddressAndChainWithUniqueId(uniqueId: UniqueId) { 12 | const fragments = uniqueId.split('_'); 13 | const address = fragments[0] as Address; 14 | const chain = parseInt(fragments[1], 10) as ChainId; 15 | return { 16 | address, 17 | chain, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/core/utils/copy.ts: -------------------------------------------------------------------------------- 1 | import { AddressZero } from '@ethersproject/constants'; 2 | import { getAddress } from 'viem'; 3 | 4 | import { triggerToast } from '~/entries/popup/components/Toast/Toast'; 5 | 6 | import { i18n } from '../languages'; 7 | import { ETH_ADDRESS } from '../references'; 8 | import { AddressOrEth } from '../types/assets'; 9 | 10 | import { truncateAddress } from './address'; 11 | 12 | export const copy = ({ 13 | value, 14 | title, 15 | description, 16 | }: { 17 | value: string; 18 | title: string; 19 | description?: string; 20 | }) => { 21 | navigator.clipboard.writeText(value); 22 | triggerToast({ title, description }); 23 | }; 24 | 25 | export const copyAddress = (address: AddressOrEth) => { 26 | if ([ETH_ADDRESS, AddressZero].includes(address)) return; 27 | copy({ 28 | title: i18n.t('wallet_header.copy_toast'), 29 | description: truncateAddress(address), 30 | value: getAddress(address), 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/core/utils/defaults.ts: -------------------------------------------------------------------------------- 1 | import { Address } from 'viem'; 2 | 3 | export const DEFAULT_ACCOUNT = 4 | '0x70c16D2dB6B00683b29602CBAB72CE0Dcbc243C4' as Address; 5 | export const DEFAULT_ACCOUNT_2 = 6 | '0x5B570F0F8E2a29B7bCBbfC000f9C7b78D45b7C35' as Address; 7 | export const DEFAULT_CHAIN_ID = '0x1'; 8 | -------------------------------------------------------------------------------- /src/core/utils/deserializeBigNumbers.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from '@ethersproject/bignumber'; 2 | 3 | export function deserializeBigNumbers(obj: T) { 4 | for (const key in obj) { 5 | const v = obj[key]; 6 | if (!v || typeof v !== 'object') continue; 7 | 8 | if ('hex' in v && 'type' in v && v.type === 'BigNumber') { 9 | (obj[key] as BigNumber) = BigNumber.from(v.hex); 10 | } else { 11 | obj[key] = deserializeBigNumbers(v); 12 | } 13 | } 14 | 15 | return obj; 16 | } 17 | -------------------------------------------------------------------------------- /src/core/utils/detectScriptType.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Detects and returns what context the script is in. 3 | */ 4 | export function detectScriptType() { 5 | const hasChromeRuntime = typeof chrome !== 'undefined' && chrome.runtime; 6 | const hasWindow = typeof window !== 'undefined'; 7 | 8 | if (hasChromeRuntime && hasWindow) { 9 | if (window.location.pathname.includes('background')) return 'background'; 10 | if (window.location.pathname.includes('contentscript')) 11 | return 'contentScript'; 12 | if ( 13 | window.location.pathname.includes('popup') && 14 | !window.location.origin.includes('trezor') 15 | ) 16 | return 'popup'; 17 | return 'contentScript'; 18 | } 19 | if (hasChromeRuntime && !hasWindow) return 'background'; 20 | if (!hasChromeRuntime && hasWindow) return 'inpage'; 21 | throw new Error('Undetected script.'); 22 | } 23 | 24 | export type ScriptType = ReturnType; 25 | -------------------------------------------------------------------------------- /src/core/utils/dimensions.ts: -------------------------------------------------------------------------------- 1 | export const POPUP_DIMENSIONS = { 2 | width: 360, 3 | height: 600, 4 | }; 5 | 6 | export const TESTNET_MODE_BAR_HEIGHT = 35; 7 | 8 | export const INJECTED_NOTIFICATION_DIMENSIONS = { 9 | // 161 (figma width spec) + 48 (radius shadow) since we need space for the shadow to be visible in the iframe 10 | width: '209px', 11 | // 40 (figma height spec) + 48 (radius shadow) + 16 (vertical shadow), since we need space for the shadow to be visible in the iframe 12 | height: '122px', 13 | // 9 (figma top spec) - 41 (extra iframe height for shadow, 122 - 40 /2 ) 14 | // since we need space for the shadow to be visible in the iframe 15 | top: '-32px', 16 | right: '50px', 17 | }; 18 | -------------------------------------------------------------------------------- /src/core/utils/draggable.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DraggableStateSnapshot, 3 | DraggingStyle, 4 | NotDraggingStyle, 5 | } from 'react-beautiful-dnd'; 6 | 7 | export function reorder( 8 | list: Iterable, 9 | startIndex: number, 10 | endIndex: number, 11 | ) { 12 | const result = Array.from(list); 13 | const [removed] = result.splice(startIndex, 1); 14 | result.splice(endIndex, 0, removed); 15 | 16 | return result; 17 | } 18 | 19 | export const getDraggableItemStyle = ( 20 | style: DraggingStyle | NotDraggingStyle | undefined, 21 | { dropAnimation }: Pick, 22 | ) => { 23 | if (!dropAnimation) return style; 24 | const { moveTo, curve } = dropAnimation; 25 | return { 26 | ...style, 27 | transform: `translate(${moveTo.x}px, ${moveTo.y}px) scale(1)`, 28 | transition: `all ${curve} .5s`, 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /src/core/utils/localJson.ts: -------------------------------------------------------------------------------- 1 | export async function fetchJsonLocally(filename: string) { 2 | try { 3 | const req = await fetch(chrome.runtime.getURL(`json/${filename}`)); 4 | const json = await req.json(); 5 | return json; 6 | } catch (e) { 7 | return {}; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/core/utils/lockdown.ts: -------------------------------------------------------------------------------- 1 | if (!navigator.userAgent.toLowerCase().includes('firefox')) { 2 | [ 3 | Object, 4 | Object.prototype, 5 | Function, 6 | Function.prototype, 7 | Array, 8 | Array.prototype, 9 | String, 10 | String.prototype, 11 | Number, 12 | Number.prototype, 13 | Boolean, 14 | Boolean.prototype, 15 | ].forEach(Object.freeze); 16 | } 17 | export {}; 18 | -------------------------------------------------------------------------------- /src/core/utils/react.ts: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | export const hasChildren = (children: ReactNode) => { 4 | return React.Children.toArray(children).some( 5 | (child) => 6 | !!child && 7 | typeof child === 'object' && 8 | `type` in child && 9 | child.type !== null, 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /src/core/utils/settings.ts: -------------------------------------------------------------------------------- 1 | import { SessionStorage } from '../storage'; 2 | import { KeychainWallet } from '../types/keychainTypes'; 3 | 4 | export const setSettingWallets = (settingsWallet: null | KeychainWallet) => { 5 | SessionStorage.set('settingsWallet', settingsWallet); 6 | }; 7 | 8 | export const getSettingWallets = async (): Promise => { 9 | return SessionStorage.get('settingsWallet'); 10 | }; 11 | -------------------------------------------------------------------------------- /src/core/utils/strings.ts: -------------------------------------------------------------------------------- 1 | export const isLowerCaseMatch = (a?: string, b?: string) => 2 | a?.toLowerCase() === b?.toLowerCase(); 3 | 4 | export const capitalize = (s = '') => s.charAt(0).toUpperCase() + s.slice(1); 5 | 6 | export const truncateString = (txt = '', maxLength = 22) => { 7 | return `${txt?.slice(0, maxLength)}${txt.length > maxLength ? '…' : ''}`; 8 | }; 9 | -------------------------------------------------------------------------------- /src/core/utils/types.ts: -------------------------------------------------------------------------------- 1 | import '@total-typescript/ts-reset'; 2 | 3 | export type Modify = Omit & R; 4 | -------------------------------------------------------------------------------- /src/core/utils/userChains.ts: -------------------------------------------------------------------------------- 1 | import { type Chain } from 'viem/chains'; 2 | 3 | import { useNetworkStore } from '../state/networks/networks'; 4 | 5 | export const sortNetworks = (order: number[], chains: Chain[]) => { 6 | const chainIdsBasedOnMainnetId = useNetworkStore 7 | .getState() 8 | .getBackendChainIdsByMainnetId(); 9 | const allChainsOrder = order 10 | ?.map((chainId) => { 11 | if (chainIdsBasedOnMainnetId[chainId]) { 12 | return [...chainIdsBasedOnMainnetId[chainId], chainId]; 13 | } 14 | return [chainId]; 15 | }) 16 | ?.flat(); 17 | const ordered = chains.sort((a, b) => { 18 | const aIndex = allChainsOrder.indexOf(a.id); 19 | const bIndex = allChainsOrder.indexOf(b.id); 20 | if (aIndex === -1) return bIndex === -1 ? 0 : 1; 21 | if (bIndex === -1) return -1; 22 | return aIndex - bIndex; 23 | }); 24 | return ordered; 25 | }; 26 | -------------------------------------------------------------------------------- /src/design-system/components/AnimatedRoute/AnimatedRoute.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { 4 | POPUP_DIMENSIONS, 5 | TESTNET_MODE_BAR_HEIGHT, 6 | } from '~/core/utils/dimensions'; 7 | 8 | export const animatedRouteStyles = style({ 9 | minHeight: POPUP_DIMENSIONS.height, 10 | }); 11 | 12 | export const animatedRouteTestnetModeStyles = style({ 13 | minHeight: POPUP_DIMENSIONS.height - TESTNET_MODE_BAR_HEIGHT, 14 | }); 15 | -------------------------------------------------------------------------------- /src/design-system/components/Button/Button.docs.tsx: -------------------------------------------------------------------------------- 1 | import { createDocs } from '../../docs/createDocs'; 2 | 3 | import { 4 | basic, 5 | colors, 6 | emojis, 7 | sizes, 8 | symbols, 9 | widths, 10 | } from './Button.examples'; 11 | 12 | const button = createDocs({ 13 | name: 'Button', 14 | category: 'Components', 15 | examples: [basic, colors, sizes, widths, emojis, symbols], 16 | }); 17 | 18 | export default button; 19 | -------------------------------------------------------------------------------- /src/design-system/components/Button/ButtonOverflow.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from 'framer-motion'; 2 | import React, { CSSProperties, ReactNode } from 'react'; 3 | 4 | import { transformScales, transitions } from '../../styles/designTokens'; 5 | import { Box } from '../Box/Box'; 6 | 7 | interface ButtonOverflowProps { 8 | children: ReactNode; 9 | style?: CSSProperties; 10 | testId?: string; 11 | } 12 | export function ButtonOverflow({ children, testId }: ButtonOverflowProps) { 13 | return ( 14 | 22 | {children} 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /src/design-system/components/ButtonSymbol/ButtonSymbol.css.ts: -------------------------------------------------------------------------------- 1 | import { styleVariants } from '@vanilla-extract/css'; 2 | 3 | import { buttonHeights } from '../Button/ButtonWrapper.css'; 4 | 5 | export const widthStyles = styleVariants(buttonHeights, (height) => [ 6 | { width: height }, 7 | ]); 8 | -------------------------------------------------------------------------------- /src/design-system/components/ButtonSymbol/ButtonSymbol.docs.tsx: -------------------------------------------------------------------------------- 1 | import { createDocs } from '../../docs/createDocs'; 2 | 3 | import { basic, colors, sizes } from './ButtonSymbol.examples'; 4 | 5 | const buttonSymbol = createDocs({ 6 | name: 'ButtonSymbol', 7 | category: 'Components', 8 | examples: [basic, colors, sizes], 9 | }); 10 | 11 | export default buttonSymbol; 12 | -------------------------------------------------------------------------------- /src/design-system/components/Columns/Columns.css.ts: -------------------------------------------------------------------------------- 1 | import { styleVariants } from '@vanilla-extract/css'; 2 | import { calc } from '@vanilla-extract/css-utils'; 3 | 4 | import { gapVar } from './../../styles/core.css'; 5 | 6 | const columnWidths = { 7 | '1/2': [1, 2], 8 | '1/3': [1, 3], 9 | '1/4': [1, 4], 10 | '1/5': [1, 5], 11 | '2/3': [2, 3], 12 | '2/5': [2, 5], 13 | '3/4': [3, 4], 14 | '3/5': [3, 5], 15 | '4/5': [4, 5], 16 | } as const; 17 | 18 | export const width = styleVariants(columnWidths, ([numerator, denominator]) => { 19 | const gapOffset = calc.subtract( 20 | gapVar, 21 | calc(gapVar).divide(denominator).multiply(numerator), 22 | ); 23 | 24 | return { 25 | width: calc.subtract(`${(numerator * 100) / denominator}%`, gapOffset), 26 | }; 27 | }); 28 | -------------------------------------------------------------------------------- /src/design-system/components/Input/Input.docs.tsx: -------------------------------------------------------------------------------- 1 | import { createDocs } from '../../docs/createDocs'; 2 | 3 | import { basic } from './Input.examples'; 4 | 5 | const input = createDocs({ 6 | name: 'Input', 7 | category: 'Components', 8 | examples: [basic], 9 | }); 10 | 11 | export default input; 12 | -------------------------------------------------------------------------------- /src/design-system/components/Input/Input.examples.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { createExample } from '../../docs/createDocs'; 4 | import source from '../../docs/utils/source.macro'; 5 | import { Inline } from '../Inline/Inline'; 6 | 7 | import { Input } from './Input'; 8 | 9 | export const basic = createExample({ 10 | name: 'Basic usage', 11 | showThemes: true, 12 | Example: () => 13 | source( 14 | 15 | 16 | 17 | 18 | , 19 | ), 20 | }); 21 | -------------------------------------------------------------------------------- /src/design-system/components/Inset/Inset.docs.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Paragraph } from '../../docs/components/Paragraph'; 4 | import { TextInline } from '../../docs/components/TextInline'; 5 | import { createDocs } from '../../docs/createDocs'; 6 | 7 | import { 8 | basicUsage, 9 | bottomSpace, 10 | horizontalSpace, 11 | leftSpace, 12 | rightSpace, 13 | topSpace, 14 | verticalSpace, 15 | } from './Inset.examples'; 16 | 17 | const inset = createDocs({ 18 | name: 'Inset', 19 | category: 'Layout', 20 | description: ( 21 | 22 | Renders a container with padding. 23 | 24 | ), 25 | examples: [ 26 | basicUsage, 27 | horizontalSpace, 28 | verticalSpace, 29 | bottomSpace, 30 | leftSpace, 31 | rightSpace, 32 | topSpace, 33 | ], 34 | }); 35 | 36 | export default inset; 37 | -------------------------------------------------------------------------------- /src/design-system/components/Inset/Inset.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | import { Space } from '../../styles/designTokens'; 4 | import { Box } from '../Box/Box'; 5 | 6 | interface InsetProps { 7 | space?: Space; 8 | horizontal?: Space; 9 | vertical?: Space; 10 | top?: Space; 11 | bottom?: Space; 12 | left?: Space; 13 | right?: Space; 14 | children?: ReactNode; 15 | } 16 | 17 | export function Inset({ 18 | children, 19 | space, 20 | horizontal, 21 | vertical, 22 | top, 23 | bottom, 24 | left, 25 | right, 26 | }: InsetProps) { 27 | return ( 28 | 34 | {children} 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /src/design-system/components/Lens/Lens.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { 4 | accentColorAsHsl, 5 | avatarColorAsHsl, 6 | transparentAccentColorAsHsl, 7 | transparentAvatarColorAsHsl, 8 | } from '../../styles/core.css'; 9 | 10 | export const accentFocusVisibleStyle = style({ 11 | selectors: { 12 | '&:focus': { 13 | backgroundColor: transparentAccentColorAsHsl, 14 | outline: '1px solid', 15 | outlineColor: accentColorAsHsl, 16 | }, 17 | }, 18 | }); 19 | 20 | export const accentMenuFocusVisibleStyle = style({ 21 | selectors: { 22 | '&:focus': { 23 | backgroundColor: transparentAccentColorAsHsl, 24 | }, 25 | }, 26 | }); 27 | 28 | export const avatarFocusVisibleStyle = style({ 29 | selectors: { 30 | '&:focus': { 31 | backgroundColor: transparentAvatarColorAsHsl, 32 | outline: '1px solid', 33 | outlineColor: avatarColorAsHsl, 34 | }, 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /src/design-system/components/Rows/Rows.css.ts: -------------------------------------------------------------------------------- 1 | import { styleVariants } from '@vanilla-extract/css'; 2 | import { calc } from '@vanilla-extract/css-utils'; 3 | 4 | import { gapVar } from './../../styles/core.css'; 5 | 6 | const rowHeights = { 7 | '1/2': [1, 2], 8 | '1/3': [1, 3], 9 | '1/4': [1, 4], 10 | '1/5': [1, 5], 11 | '2/3': [2, 3], 12 | '2/5': [2, 5], 13 | '3/4': [3, 4], 14 | '3/5': [3, 5], 15 | '4/5': [4, 5], 16 | } as const; 17 | 18 | export const height = styleVariants(rowHeights, ([numerator, denominator]) => { 19 | const gapOffset = calc.subtract( 20 | gapVar, 21 | calc(gapVar).divide(denominator).multiply(numerator), 22 | ); 23 | 24 | return { 25 | height: calc.subtract(`${(numerator * 100) / denominator}%`, gapOffset), 26 | }; 27 | }); 28 | -------------------------------------------------------------------------------- /src/design-system/components/Separator/Separator.css.ts: -------------------------------------------------------------------------------- 1 | import { styleVariants } from '@vanilla-extract/css'; 2 | 3 | import { semanticColorVars } from './../../styles/core.css'; 4 | import { SeparatorColor, separatorColors } from './../../styles/designTokens'; 5 | 6 | const colors = Object.assign( 7 | {}, 8 | ...separatorColors.map((separatorColor) => ({ 9 | [separatorColor]: separatorColor, 10 | })), 11 | ) as Record; 12 | 13 | export const color = styleVariants(colors, (foregroundColor) => ({ 14 | backgroundColor: semanticColorVars.foregroundColors[foregroundColor], 15 | })); 16 | -------------------------------------------------------------------------------- /src/design-system/components/Separator/Separator.docs.tsx: -------------------------------------------------------------------------------- 1 | import { createDocs } from '../../docs/createDocs'; 2 | 3 | import { basic, colors, weights } from './Separator.examples'; 4 | 5 | const separator = createDocs({ 6 | name: 'Separator', 7 | category: 'Components', 8 | examples: [basic, colors, weights], 9 | }); 10 | 11 | export default separator; 12 | -------------------------------------------------------------------------------- /src/design-system/components/Separator/Separator.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from 'react'; 2 | 3 | import { StrokeWeight, strokeWeights } from '../../styles/designTokens'; 4 | import { Box } from '../Box/Box'; 5 | 6 | import * as styles from './Separator.css'; 7 | 8 | interface SeparatorProps { 9 | strokeWeight?: StrokeWeight; 10 | color?: keyof typeof styles.color; 11 | width?: CSSProperties['width']; 12 | } 13 | 14 | export function Separator({ 15 | color = 'separator', 16 | strokeWeight = '1px', 17 | width, 18 | }: SeparatorProps) { 19 | return ( 20 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/design-system/components/Skeleton/Skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { MotionProps, motion } from 'framer-motion'; 2 | import { CSSProperties } from 'react'; 3 | 4 | import { Box } from '../Box/Box'; 5 | 6 | import { skeletonCircle, skeletonLine } from './Skeleton.css'; 7 | 8 | export function Skeleton({ 9 | height, 10 | width, 11 | circle, 12 | style, 13 | ...motionProps 14 | }: { 15 | height: string; 16 | width: string; 17 | circle?: boolean; 18 | style?: CSSProperties; 19 | } & MotionProps) { 20 | return ( 21 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /src/design-system/components/Symbol/Symbol.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | export const boxedStyle = style({ 4 | backgroundColor: 'rgba(245, 248, 255, 0.16)', 5 | borderWidth: '1px', 6 | borderRadius: '5px', 7 | borderColor: 'rgba(255, 255, 255, 0.03)', 8 | height: '20px', 9 | width: '20px', 10 | }); 11 | -------------------------------------------------------------------------------- /src/design-system/components/Symbol/Symbol.docs.tsx: -------------------------------------------------------------------------------- 1 | import { createDocs } from '../../docs/createDocs'; 2 | 3 | import { basic, colors, sizes, weights } from './Symbol.examples'; 4 | 5 | const symbol = createDocs({ 6 | name: 'Symbol', 7 | category: 'Components', 8 | examples: [basic, sizes, weights, colors], 9 | }); 10 | 11 | export default symbol; 12 | -------------------------------------------------------------------------------- /src/design-system/components/Symbol/gradients.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const rainbowGradient = ( 4 | 12 | 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /src/design-system/components/Text/Text.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { accentColorAsHsl } from '../../styles/core.css'; 4 | 5 | export const selectionStyle = style({ 6 | selectors: { 7 | '&::selection': { 8 | background: accentColorAsHsl, 9 | color: 'black', 10 | }, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /src/design-system/docs/.eslintignore: -------------------------------------------------------------------------------- 1 | next-env.d.ts 2 | next.config.js -------------------------------------------------------------------------------- /src/design-system/docs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['rainbow', 'next/core-web-vitals'], 4 | plugins: ['prettier'], 5 | rules: { 6 | 'import/no-default-export': 'off', 7 | 'react/jsx-props-no-spreading': 'off', 8 | 'prettier/prettier': ['error', require('./.prettierrc.js')], 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /src/design-system/docs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /src/design-system/docs/.playroom/FrameComponent.js: -------------------------------------------------------------------------------- 1 | import './global.css.ts'; 2 | import React, { Fragment, useEffect } from 'react'; 3 | import { initThemingBody, initThemingCritical } from './components'; 4 | 5 | export default ({ children, themeName }) => { 6 | useEffect(() => { 7 | initThemingCritical({ defaultTheme: themeName, enableSaved: false }); 8 | initThemingBody() 9 | }, []) 10 | return ( 11 |
12 | {children} 13 |
14 | ); 15 | } -------------------------------------------------------------------------------- /src/design-system/docs/.playroom/components.ts: -------------------------------------------------------------------------------- 1 | export * from '../../index'; -------------------------------------------------------------------------------- /src/design-system/docs/.playroom/global.css.ts: -------------------------------------------------------------------------------- 1 | import { globalStyle } from "@vanilla-extract/css"; 2 | 3 | globalStyle('html, body', { 4 | margin: 0, 5 | padding: 0, 6 | }) -------------------------------------------------------------------------------- /src/design-system/docs/.playroom/themes.ts: -------------------------------------------------------------------------------- 1 | export const light = {}; 2 | export const dark = {}; 3 | -------------------------------------------------------------------------------- /src/design-system/docs/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: "always", 3 | endOfLine: "lf", 4 | printWidth: 80, 5 | semi: true, 6 | singleQuote: true, 7 | tabWidth: 2, 8 | trailingComma: "all", 9 | }; 10 | -------------------------------------------------------------------------------- /src/design-system/docs/assets.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-default-export */ 2 | 3 | declare module '*.woff2' { 4 | const path: string; 5 | export default path; 6 | } 7 | -------------------------------------------------------------------------------- /src/design-system/docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['macros'], 3 | presets: ['next/babel'], 4 | }; 5 | -------------------------------------------------------------------------------- /src/design-system/docs/components/ButtonLink.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Box } from '../../components/Box/Box'; 3 | 4 | import { ButtonOverlay, ButtonOverlayProps } from './Button'; 5 | 6 | type ButtonLinkProps = ButtonOverlayProps & { 7 | href: string; 8 | }; 9 | 10 | export const ButtonLink = ({ 11 | children, 12 | color, 13 | iconBefore, 14 | href, 15 | size, 16 | }: ButtonLinkProps) => ( 17 | 18 | 19 | {children} 20 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /src/design-system/docs/components/Code.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | export const fontStyle = style({ 4 | fontFamily: 'SFMono', 5 | fontSize: '0.9em', 6 | letterSpacing: '-0.3px', 7 | }); 8 | -------------------------------------------------------------------------------- /src/design-system/docs/components/Code.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import { Box } from '../../components/Box/Box'; 3 | import { fontStyle } from './Code.css'; 4 | 5 | export const Code = ({ children }: { children: ReactNode }) => ( 6 | 13 | {children} 14 | 15 | ); 16 | -------------------------------------------------------------------------------- /src/design-system/docs/components/Paragraph.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import { Text } from '../../components/Text/Text'; 3 | 4 | export const Paragraph = ({ children }: { children: ReactNode }) => ( 5 | 6 | {children} 7 | 8 | ); 9 | -------------------------------------------------------------------------------- /src/design-system/docs/components/Placeholder.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Box } from '../../components/Box/Box'; 3 | 4 | export const Placeholder = ({ 5 | className, 6 | height = 60, 7 | width, 8 | }: { 9 | className?: string; 10 | height?: number | '100%'; 11 | width?: number | '100%'; 12 | }) => { 13 | return ( 14 | 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/design-system/docs/components/TextInline.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import clsx from 'clsx'; 3 | 4 | import { Box } from '../../components/Box/Box'; 5 | import { boxStyles, TextStyles, textStyles } from '../../styles/core.css'; 6 | 7 | export const TextInline = ({ 8 | children, 9 | color, 10 | highlight, 11 | weight, 12 | }: { 13 | children: ReactNode; 14 | color?: TextStyles['color']; 15 | highlight?: boolean; 16 | weight?: TextStyles['fontWeight']; 17 | }) => ( 18 | 30 | {children} 31 | 32 | ); 33 | -------------------------------------------------------------------------------- /src/design-system/docs/components/TextLink.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | import { textStyles } from '../../styles/core.css'; 3 | 4 | export const textLink = style([ 5 | textStyles({ color: 'accent' }), 6 | { 7 | textUnderlinePosition: 'from-font', 8 | ':hover': { 9 | textDecoration: 'underline', 10 | }, 11 | }, 12 | ]); 13 | -------------------------------------------------------------------------------- /src/design-system/docs/components/TextLink.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import { Box } from '../../components/Box/Box'; 3 | import * as styles from './TextLink.css'; 4 | 5 | export const TextLink = ({ 6 | children, 7 | href, 8 | }: { 9 | children: ReactNode; 10 | href: string; 11 | }) => ( 12 | 19 | {children} 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /src/design-system/docs/createDocs.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Source } from './utils/source.macro'; 3 | 4 | export type Docs = { 5 | name?: string; 6 | category: 'Components' | 'Contexts' | 'Layout' | 'Tokens'; 7 | description?: JSX.Element | JSX.Element[]; 8 | examples?: Example[]; 9 | }; 10 | 11 | export type Example = { 12 | enablePlayroom?: boolean; 13 | enableCodeSnippet?: boolean; 14 | description?: JSX.Element | JSX.Element[]; 15 | Example?: () => Source; 16 | examples?: Example[]; 17 | name?: string; 18 | showFrame?: boolean; 19 | showThemes?: boolean | 'toggle'; 20 | subTitle?: string; 21 | wrapper?: (children: React.ReactNode) => React.ReactNode; 22 | }; 23 | 24 | export function createDocs(docs: Docs) { 25 | return docs; 26 | } 27 | 28 | export function createExample(example: Example) { 29 | return example; 30 | } 31 | -------------------------------------------------------------------------------- /src/design-system/docs/icons/ChevronDownIcon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | const ChevronDownIcon = () => ( 4 | 5 | 9 | 10 | ); 11 | 12 | export default ChevronDownIcon; 13 | -------------------------------------------------------------------------------- /src/design-system/docs/icons/ChevronUpIcon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | const ChevronUpIcon = () => ( 4 | 5 | 9 | 10 | ); 11 | 12 | export default ChevronUpIcon; 13 | -------------------------------------------------------------------------------- /src/design-system/docs/public/10a057a19c05e5222c23e27f8721e315.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/10a057a19c05e5222c23e27f8721e315.woff2 -------------------------------------------------------------------------------- /src/design-system/docs/public/7d078eef80cc7bd36f5d2634b94302c2.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/7d078eef80cc7bd36f5d2634b94302c2.woff2 -------------------------------------------------------------------------------- /src/design-system/docs/public/SFMonoMedium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/SFMonoMedium.woff -------------------------------------------------------------------------------- /src/design-system/docs/public/a10063243e691df6f06e65b34da0fe66.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/a10063243e691df6f06e65b34da0fe66.woff2 -------------------------------------------------------------------------------- /src/design-system/docs/public/a3d1d0ad4ba794e2473f30fac79196dc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/a3d1d0ad4ba794e2473f30fac79196dc.woff2 -------------------------------------------------------------------------------- /src/design-system/docs/public/cf4fe3e1b6836782be2dd5f5399cd86d.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/cf4fe3e1b6836782be2dd5f5399cd86d.woff2 -------------------------------------------------------------------------------- /src/design-system/docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/favicon.ico -------------------------------------------------------------------------------- /src/design-system/docs/public/initThemingBody.mjs: -------------------------------------------------------------------------------- 1 | var e={lightTheme:{lightContext:"lt-lc",darkContext:"lt-dc"},darkTheme:{lightContext:"dt-lc",darkContext:"dt-dc"}};function l(){document.body.classList.add(e.lightTheme.lightContext,e.darkTheme.darkContext)}export{l as initThemingBody}; 2 | -------------------------------------------------------------------------------- /src/design-system/docs/public/initThemingCritical.mjs: -------------------------------------------------------------------------------- 1 | var n={lightTheme:"lt",darkTheme:"dt"};function r(){let e=typeof localStorage<"u"?localStorage.getItem("rainbow.theme"):null,t=typeof window<"u"?window.matchMedia("(prefers-color-scheme: light)").matches?"light":"dark":null;return{savedTheme:e,systemTheme:t}}function i({defaultTheme:e,enableSaved:t=!0}={}){let m=o=>{document.documentElement.classList.remove(...Object.values(n)),document.documentElement.classList.add(n[o==="dark"?"darkTheme":"lightTheme"])},s=window.matchMedia("(prefers-color-scheme: dark)"),{savedTheme:l,systemTheme:a}=r();m((t?l:void 0)||e||a||"dark"),l||s.addEventListener("change",({matches:o})=>{m(o?"dark":"light")})}export{i as initThemingCritical}; 2 | -------------------------------------------------------------------------------- /src/design-system/docs/public/rainbow-icon@128w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/rainbow-icon@128w.png -------------------------------------------------------------------------------- /src/design-system/docs/public/rainbow-icon@256w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/rainbow-icon@256w.png -------------------------------------------------------------------------------- /src/design-system/docs/public/rainbow-icon@512w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/docs/public/rainbow-icon@512w.png -------------------------------------------------------------------------------- /src/design-system/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /src/design-system/docs/types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Source } from './utils/source.macro'; 3 | 4 | export type Docs = { 5 | name?: string; 6 | category: 'Contexts' | 'Layout' | 'Tokens'; 7 | description?: JSX.Element | JSX.Element[]; 8 | examples?: Example[]; 9 | }; 10 | 11 | export type Example = { 12 | enablePlayroom?: boolean; 13 | enableCodeSnippet?: boolean; 14 | description?: JSX.Element | JSX.Element[]; 15 | Example?: () => Source; 16 | examples?: Example[]; 17 | name?: string; 18 | showFrame?: boolean; 19 | showThemes?: boolean | 'toggle'; 20 | subTitle?: string; 21 | wrapper?: (children: React.ReactNode) => React.ReactNode; 22 | }; 23 | -------------------------------------------------------------------------------- /src/design-system/docs/utils/source.macro.d.ts: -------------------------------------------------------------------------------- 1 | export type Source = { code: string; value: Value }; 2 | 3 | export default function source(value: Value): Source; 4 | -------------------------------------------------------------------------------- /src/design-system/docs/utils/source.macro.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-commonjs */ 2 | /* eslint-disable @typescript-eslint/no-var-requires */ 3 | const { default: generate } = require('@babel/generator'); 4 | const { createMacro } = require('babel-plugin-macros'); 5 | 6 | module.exports = createMacro(({ babel: { types: t }, references }) => { 7 | if (!references.default) { 8 | return; 9 | } 10 | 11 | references.default.forEach(({ parentPath }) => { 12 | const value = parentPath.node.arguments[0] || t.identifier('undefined'); 13 | const code = t.stringLiteral(generate(value).code); 14 | 15 | return parentPath.replaceWith( 16 | t.objectExpression([ 17 | t.objectProperty(t.identifier('code'), code), 18 | t.objectProperty(t.identifier('value'), value), 19 | ]), 20 | ); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/design-system/styles/autocompleteInputStyles.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { transparentAccentColorAsHsl } from './core.css'; 4 | 5 | export const selectedItem = style({ 6 | transition: 'none', 7 | selectors: { 8 | '&[data-selected]': { 9 | backgroundColor: transparentAccentColorAsHsl, 10 | transition: 'none', 11 | }, 12 | }, 13 | }); 14 | -------------------------------------------------------------------------------- /src/design-system/styles/fonts/SFMono-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/styles/fonts/SFMono-bold.woff2 -------------------------------------------------------------------------------- /src/design-system/styles/fonts/SFMono-semibold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/styles/fonts/SFMono-semibold.woff2 -------------------------------------------------------------------------------- /src/design-system/styles/fonts/subset-SFRounded-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/styles/fonts/subset-SFRounded-Bold.woff2 -------------------------------------------------------------------------------- /src/design-system/styles/fonts/subset-SFRounded-Heavy.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/styles/fonts/subset-SFRounded-Heavy.woff2 -------------------------------------------------------------------------------- /src/design-system/styles/fonts/subset-SFRounded-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/styles/fonts/subset-SFRounded-Medium.woff2 -------------------------------------------------------------------------------- /src/design-system/styles/fonts/subset-SFRounded-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/styles/fonts/subset-SFRounded-Regular.woff2 -------------------------------------------------------------------------------- /src/design-system/styles/fonts/subset-SFRounded-Semibold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/styles/fonts/subset-SFRounded-Semibold.woff2 -------------------------------------------------------------------------------- /src/design-system/styles/hslObjectForColor.ts: -------------------------------------------------------------------------------- 1 | import chroma from 'chroma-js'; 2 | 3 | export function hslObjectForColor(color: string) { 4 | const [hue, saturation, lightness] = chroma(color).hsl(); 5 | 6 | return { 7 | hue: isNaN(hue) ? '0' : String(hue), 8 | saturation: `${saturation * 100}%`, 9 | lightness: `${lightness * 100}%`, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/design-system/styles/initThemingBody.ts: -------------------------------------------------------------------------------- 1 | import { themeClasses } from './theme'; 2 | 3 | export function initThemingBody() { 4 | // Set the initial color contexts to match their respective themes 5 | document.body.classList.add( 6 | themeClasses.lightTheme.lightContext, 7 | themeClasses.darkTheme.darkContext, 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/design-system/styles/initThemingLocal.ts: -------------------------------------------------------------------------------- 1 | import { useCurrentThemeStore } from '~/core/state/currentSettings/currentTheme'; 2 | 3 | export function initThemingLocal() { 4 | const localTheme = localStorage.getItem('theme'); 5 | if (!localTheme) { 6 | const currentTheme = useCurrentThemeStore.getState().currentTheme; 7 | localStorage.setItem('theme', currentTheme); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/design-system/styles/radii.docs.tsx: -------------------------------------------------------------------------------- 1 | import { borderRadius } from '../components/Box/Box.examples'; 2 | import { createDocs } from '../docs/createDocs'; 3 | 4 | const radii = createDocs({ 5 | name: 'Radii', 6 | category: 'Tokens', 7 | description: borderRadius.description, 8 | examples: [ 9 | { 10 | Example: borderRadius.Example, 11 | }, 12 | ], 13 | }); 14 | 15 | export default radii; 16 | -------------------------------------------------------------------------------- /src/design-system/styles/rowTransparentAccentHighlight.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { transparentAccentColorAsHsl } from '~/design-system/styles/core.css'; 4 | 5 | export const rowTransparentAccentHighlight = style([ 6 | { 7 | ':hover': { 8 | backgroundColor: transparentAccentColorAsHsl, 9 | }, 10 | }, 11 | ]); 12 | -------------------------------------------------------------------------------- /src/design-system/styles/shadows.docs.tsx: -------------------------------------------------------------------------------- 1 | import { shadows as boxShadows } from '../components/Box/Box.examples'; 2 | import { createDocs } from '../docs/createDocs'; 3 | 4 | const shadows = createDocs({ 5 | name: 'Shadows', 6 | category: 'Tokens', 7 | description: boxShadows.description, 8 | examples: [...(boxShadows.examples || [])], 9 | }); 10 | 11 | export default shadows; 12 | -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Italic.ttf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Black.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Black.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Bold.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Heavy.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Heavy.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Light.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Medium.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Regular.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Semibold.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Thin.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Thin.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro-Text-Ultralight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro-Text-Ultralight.otf -------------------------------------------------------------------------------- /src/design-system/symbols/sources/SF-Pro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/src/design-system/symbols/sources/SF-Pro.ttf -------------------------------------------------------------------------------- /src/entries/background/handlers/handleDisconnect.ts: -------------------------------------------------------------------------------- 1 | import { SessionStorage } from '~/core/storage'; 2 | 3 | const POPUP_INSTANCE_DATA_EXPIRY = 180000; 4 | export function handleDisconnect() { 5 | chrome.runtime.onConnect.addListener(function (port) { 6 | if (port.name === 'popup') { 7 | port.onDisconnect.addListener(async function () { 8 | await SessionStorage.set( 9 | 'expiry', 10 | Date.now() + POPUP_INSTANCE_DATA_EXPIRY, 11 | ); 12 | }); 13 | } 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /src/entries/background/handlers/handleKeepAlive.ts: -------------------------------------------------------------------------------- 1 | import { initializeMessenger } from '~/core/messengers'; 2 | 3 | const messenger = initializeMessenger({ connect: 'popup' }); 4 | 5 | /** 6 | * Handles wallet related requests 7 | */ 8 | export const handleKeepAlive = () => { 9 | messenger.reply('ping', async () => { 10 | return { payload: 'pong' }; 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/entries/background/handlers/handlePrefetchMetadata.ts: -------------------------------------------------------------------------------- 1 | import { initializeMessenger } from '~/core/messengers'; 2 | import { prefetchDappMetadata } from '~/core/resources/metadata/dapp'; 3 | 4 | const bridgeMessenger = initializeMessenger({ connect: 'inpage' }); 5 | 6 | export const handlePrefetchDappMetadata = () => { 7 | bridgeMessenger.reply( 8 | 'rainbow_prefetchDappMetadata', 9 | async (href: string) => { 10 | prefetchDappMetadata({ url: href }); 11 | }, 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /src/entries/popup/App.test.disabled.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | import * as React from 'react'; 3 | import { test } from 'vitest'; 4 | 5 | import { App } from './App'; 6 | 7 | test('renders the app', () => { 8 | render(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/entries/popup/app.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { POPUP_DIMENSIONS } from '~/core/utils/dimensions'; 4 | 5 | export const appContainer = style({ 6 | position: 'relative', 7 | border: '2px solid red', 8 | background: 'transparent', 9 | pointerEvents: 'auto', 10 | zIndex: 1000000000000000, 11 | height: POPUP_DIMENSIONS.height, 12 | }); 13 | -------------------------------------------------------------------------------- /src/entries/popup/components/AppConnection/AppConnectionWalletItem/AppConnectionWalletItem.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { boxStyles } from '~/design-system'; 4 | import { transparentAccentColorAsHsl } from '~/design-system/styles/core.css'; 5 | 6 | export const appConnectionWalletItem = style([ 7 | boxStyles({ 8 | borderRadius: '12px', 9 | }), 10 | { 11 | ':hover': { 12 | backgroundColor: transparentAccentColorAsHsl, 13 | }, 14 | }, 15 | ]); 16 | -------------------------------------------------------------------------------- /src/entries/popup/components/Asterisks/Asterisks.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Inline } from '~/design-system'; 4 | import { Symbol, SymbolProps } from '~/design-system/components/Symbol/Symbol'; 5 | 6 | const Asterisks = ({ 7 | color, 8 | size, 9 | }: { 10 | color: SymbolProps['color']; 11 | size: SymbolProps['size']; 12 | }) => ( 13 | 14 | {Array(4) 15 | .fill(0) 16 | .map((_, i) => ( 17 | 24 | ))} 25 | 26 | ); 27 | export { Asterisks }; 28 | -------------------------------------------------------------------------------- /src/entries/popup/components/CommandK/references.ts: -------------------------------------------------------------------------------- 1 | import { i18n } from '~/core/languages'; 2 | 3 | export const actionLabels = { 4 | activateCommand: () => i18n.t('command_k.action_labels.activate_command'), 5 | open: () => i18n.t('command_k.action_labels.open'), 6 | openInNewTab: () => i18n.t('command_k.action_labels.open_in_new_tab'), 7 | switchToWallet: () => i18n.t('command_k.action_labels.switch_to_wallet'), 8 | sendToContact: () => i18n.t('command_k.action_labels.send_to_contact'), 9 | view: () => i18n.t('command_k.action_labels.view'), 10 | }; 11 | 12 | export const springConfig = { 13 | type: 'spring', 14 | stiffness: 1111, 15 | damping: 50, 16 | mass: 1, 17 | }; 18 | 19 | export const timingConfig = (duration?: number) => { 20 | return { 21 | duration: duration ?? 0.125, 22 | ease: [0.2, 0, 0, 1], 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /src/entries/popup/components/Draggable/draggableItem.css.ts: -------------------------------------------------------------------------------- 1 | import { styleVariants } from '@vanilla-extract/css'; 2 | 3 | import { transparentAccentColorAsHsl } from '~/design-system/styles/core.css'; 4 | 5 | const baseStyles = { 6 | borderRadius: '12px', 7 | transition: 'all .2s ease-in-out', 8 | }; 9 | 10 | export const dragabbleItem = styleVariants({ 11 | idle: { 12 | ...baseStyles, 13 | ':hover': { backgroundColor: transparentAccentColorAsHsl }, 14 | ':active': { scale: 0.96 }, 15 | cursor: 'default', 16 | }, 17 | dragging: { 18 | ...baseStyles, 19 | scale: 1.02, 20 | backgroundColor: transparentAccentColorAsHsl, 21 | backdropFilter: 'blur(12px) grayscale(100%)', 22 | cursor: 'grabbing', 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /src/entries/popup/components/DropdownMenu/RadioItemHighlightWrapper.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { transparentAccentColorAsHsl } from '~/design-system/styles/core.css'; 4 | 5 | export const RadioItemHighlightWrapper = style([ 6 | { 7 | ':hover': { 8 | backgroundColor: transparentAccentColorAsHsl, 9 | }, 10 | }, 11 | ]); 12 | -------------------------------------------------------------------------------- /src/entries/popup/components/Form/Form.tsx: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | 3 | import { Box, Stack } from '~/design-system'; 4 | 5 | interface FormProps { 6 | children: React.ReactNode; 7 | } 8 | 9 | const Form = forwardRef(function Form( 10 | { children }, 11 | ref, 12 | ) { 13 | return ( 14 | 22 | {children} 23 | 24 | ); 25 | }); 26 | 27 | export { Form }; 28 | -------------------------------------------------------------------------------- /src/entries/popup/components/FullScreen/FullScreenContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { POPUP_DIMENSIONS } from '~/core/utils/dimensions'; 4 | import { Box } from '~/design-system'; 5 | import { BackgroundColor } from '~/design-system/styles/designTokens'; 6 | 7 | import { NAVBAR_HEIGHT } from '../Navbar/Navbar'; 8 | 9 | export function FullScreenContainer({ 10 | children, 11 | background, 12 | }: { 13 | children: React.ReactNode; 14 | background?: BackgroundColor; 15 | }) { 16 | return ( 17 | 28 | {children} 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/entries/popup/components/HomeMenuRow/HomeMenuRow.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactElement } from 'react'; 2 | 3 | import { Box, Column, Columns } from '~/design-system'; 4 | 5 | export const HomeMenuRow = ({ 6 | leftComponent, 7 | centerComponent, 8 | rightComponent, 9 | testId, 10 | }: { 11 | leftComponent: ReactElement; 12 | centerComponent: ReactElement; 13 | rightComponent?: ReactElement | null; 14 | testId?: string; 15 | }) => { 16 | return ( 17 | 18 | 19 | {leftComponent} 20 | 21 | 22 | {centerComponent} 23 | {rightComponent && ( 24 | {rightComponent} 25 | )} 26 | 27 | 28 | 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/entries/popup/components/ImportWallet/useImportWalletSessionSecrets.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | import { getImportWalletSecrets } from '../../handlers/importWalletSecrets'; 4 | 5 | export const useImportWalletSessionSecrets = () => { 6 | const [secrets, setSecrets] = useState([]); 7 | 8 | useEffect(() => { 9 | let mounted = true; 10 | getImportWalletSecrets().then((secrets) => { 11 | if (mounted) setSecrets(secrets); 12 | }); 13 | return () => { 14 | mounted = false; 15 | }; 16 | }, []); 17 | 18 | return secrets; 19 | }; 20 | -------------------------------------------------------------------------------- /src/entries/popup/components/Link/Link.tsx: -------------------------------------------------------------------------------- 1 | import { LinkProps, Link as RRLink } from 'react-router-dom'; 2 | 3 | export function Link(props: LinkProps) { 4 | // eslint-disable-next-line react/jsx-props-no-spreading 5 | return ; 6 | } 7 | -------------------------------------------------------------------------------- /src/entries/popup/components/Menu/MenuContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Box, Stack } from '~/design-system'; 4 | 5 | interface MenuContainerProps { 6 | children: React.ReactNode; 7 | testId?: string; 8 | } 9 | const MenuContainer = ({ children, testId }: MenuContainerProps) => { 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | }; 16 | 17 | export { MenuContainer }; 18 | -------------------------------------------------------------------------------- /src/entries/popup/components/Navbar/Navbar.css.ts: -------------------------------------------------------------------------------- 1 | import { boxStyles } from '~/design-system'; 2 | 3 | export const navbarButtonStyles = { 4 | default: boxStyles({ 5 | background: 'surfaceSecondaryElevated', 6 | borderColor: 'buttonStroke', 7 | borderWidth: '1px', 8 | }), 9 | ghost: undefined, 10 | }; 11 | -------------------------------------------------------------------------------- /src/entries/popup/components/OnboardingKeepAlive/index.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef } from 'react'; 2 | 3 | import { initializeMessenger } from '~/core/messengers'; 4 | 5 | import { useAuth } from '../../hooks/useAuth'; 6 | 7 | export const OnboardingKeepAlive = () => { 8 | const bgMessenger = initializeMessenger({ connect: 'background' }); 9 | 10 | const { status } = useAuth(); 11 | 12 | const timer = useRef(undefined); 13 | 14 | const keepAlive = useCallback(async () => { 15 | await bgMessenger.send('ping', {}); 16 | }, [bgMessenger]); 17 | 18 | useEffect(() => { 19 | if (status !== 'READY') { 20 | if (!timer.current) { 21 | timer.current = setInterval(keepAlive, 1000); 22 | } 23 | } else { 24 | clearInterval(timer.current); 25 | } 26 | }, [keepAlive, status]); 27 | 28 | return null; 29 | }; 30 | -------------------------------------------------------------------------------- /src/entries/popup/components/Spinner/Spinner.css.ts: -------------------------------------------------------------------------------- 1 | import { keyframes, style } from '@vanilla-extract/css'; 2 | 3 | import pendingMask from 'static/assets/masks/pending_mask.png'; 4 | 5 | const maskImage = `url(${pendingMask})`; 6 | 7 | const rotate = keyframes({ 8 | '0%': { transform: 'rotate(0deg)' }, 9 | '100%': { transform: 'rotate(360deg)' }, 10 | }); 11 | 12 | export const spinnerStyle = style([ 13 | { 14 | maskImage, 15 | WebkitMaskImage: maskImage, 16 | animationName: rotate, 17 | animationDuration: '0.5s', 18 | animationTimingFunction: 'linear', 19 | animationIterationCount: 'infinite', 20 | willChange: 'transform', 21 | }, 22 | ]); 23 | -------------------------------------------------------------------------------- /src/entries/popup/components/_dev/ClearStorage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { LocalStorage } from '~/core/storage'; 4 | import { Box, Text } from '~/design-system'; 5 | 6 | export function ClearStorage() { 7 | return ( 8 | 16 | 17 | CLEAR STORAGE 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/entries/popup/handlers/importWalletSecrets.ts: -------------------------------------------------------------------------------- 1 | import { SessionStorage } from '~/core/storage'; 2 | 3 | export const getImportWalletSecrets = async () => { 4 | try { 5 | const result = await SessionStorage.get('importWalletSecrets'); 6 | return (result as string[]) || ['']; 7 | } catch (e) { 8 | console.log('Error while getting import wallet secrets: ', e); 9 | return ['']; 10 | } 11 | }; 12 | 13 | export const setImportWalletSecrets = async (importWalletSecrets: string[]) => { 14 | try { 15 | await SessionStorage.set('importWalletSecrets', importWalletSecrets); 16 | } catch (e) { 17 | console.log('Error while setting import wallet secrets: ', e); 18 | } 19 | }; 20 | 21 | export const removeImportWalletSecrets = async () => { 22 | try { 23 | await SessionStorage.remove('importWalletSecrets'); 24 | } catch (e) { 25 | console.log('Error while removing import wallet secrets: ', e); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/entries/popup/handlers/walletAction.ts: -------------------------------------------------------------------------------- 1 | import { uuid4 } from '@sentry/utils'; 2 | 3 | import { initializeMessenger } from '~/core/messengers'; 4 | 5 | const messenger = initializeMessenger({ connect: 'background' }); 6 | 7 | export const walletAction = async (action: string, payload: unknown) => { 8 | const { result, error }: { result: T; error?: string } = await messenger.send( 9 | 'wallet_action', 10 | { 11 | action, 12 | payload, 13 | }, 14 | { id: uuid4() }, 15 | ); 16 | if (error) throw new Error(error); 17 | return result; 18 | }; 19 | -------------------------------------------------------------------------------- /src/entries/popup/handlers/walletVariables.tsx: -------------------------------------------------------------------------------- 1 | import { Address } from 'viem'; 2 | 3 | export const HARDWARE_WALLETS = { 4 | MOCK_ACCOUNT: { 5 | accountsToImport: [ 6 | { 7 | address: '0x2419EB3D5E048f50D386f6217Cd5033eBfc36b83' as Address, 8 | index: 0, 9 | }, 10 | { 11 | address: '0x37bD75826582532373D738F83b913C97447b0906' as Address, 12 | index: 1, 13 | }, 14 | ], 15 | deviceId: 'lol', 16 | accountsEnabled: 2, 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/swap/index.tsx: -------------------------------------------------------------------------------- 1 | export { useSwapAssets } from './useSwapAssets'; 2 | export { useSwapDropdownDimensions } from './useSwapDropdownDimensions'; 3 | export { useSwapInputs } from './useSwapInputs'; 4 | export { useSwapQuote } from './useSwapQuote'; 5 | export { useSwapQuoteHandler } from './useSwapQuoteHandler'; 6 | export { useSwapReviewDetails } from './useSwapReviewDetails'; 7 | export { useSwapSettings } from './useSwapSettings'; 8 | export { useSwapValidations } from './useSwapValidations'; 9 | export { useSwapSlippage } from './useSwapSlippage'; 10 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/swap/useSwapDropdownDimensions.tsx: -------------------------------------------------------------------------------- 1 | import { ParsedSearchAsset } from '~/core/types/assets'; 2 | import { SearchAsset } from '~/core/types/search'; 3 | 4 | const INITIAL_TO_SWAP_HEIGHT = 452; 5 | const INITIAL_TO_RECEIVE_HEIGHT = 376; 6 | const EXTRA_INFO_HEIGHT = 24; 7 | 8 | export const useSwapDropdownDimensions = ({ 9 | assetToSell, 10 | assetToBuy, 11 | }: { 12 | assetToSell: ParsedSearchAsset | SearchAsset | null; 13 | assetToBuy: ParsedSearchAsset | SearchAsset | null; 14 | }) => { 15 | return { 16 | toSellInputHeight: 17 | INITIAL_TO_SWAP_HEIGHT - (!assetToSell ? 0 : EXTRA_INFO_HEIGHT), 18 | toBuyInputHeight: 19 | INITIAL_TO_RECEIVE_HEIGHT - 20 | (!assetToSell ? 0 : EXTRA_INFO_HEIGHT) - 21 | (!assetToBuy ? 0 : EXTRA_INFO_HEIGHT), 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useComponentWillUnmount.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | export default function useComponentWillUnmount(handler: VoidFunction) { 4 | const cb = useRef(handler); 5 | cb.current = handler; 6 | useEffect(() => { 7 | return () => { 8 | cb.current(); 9 | }; 10 | }, []); 11 | } 12 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useCurrentWalletType.tsx: -------------------------------------------------------------------------------- 1 | import { useCurrentAddressStore } from '~/core/state'; 2 | 3 | import { useWallets } from './useWallets'; 4 | 5 | export const useCurrentWalletTypeAndVendor = () => { 6 | const { currentAddress: address } = useCurrentAddressStore(); 7 | const { allWallets } = useWallets(); 8 | 9 | const wallet = allWallets.find((wallet) => wallet.address === address); 10 | return { type: wallet?.type, vendor: wallet?.vendor }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useDebounce.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export function useDebounce(value: T, delay: number) { 4 | // State and setters for debounced value 5 | const [debouncedValue, setDebouncedValue] = useState(value); 6 | useEffect( 7 | () => { 8 | // Update debounced value after delay 9 | const handler = setTimeout(() => { 10 | setDebouncedValue(value); 11 | }, delay); 12 | // Cancel the timeout if value changes (also on delay change or unmount) 13 | // This is how we prevent debounced value from updating if value is changed ... 14 | // .. within the delay period. Timeout gets cleared and restarted. 15 | return () => { 16 | clearTimeout(handler); 17 | }; 18 | }, 19 | [value, delay], // Only re-call effect if value or delay changes 20 | ); 21 | return debouncedValue; 22 | } 23 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useDefaultTxSpeed.ts: -------------------------------------------------------------------------------- 1 | import { useDefaultTxSpeedStore } from '~/core/state/currentSettings/defaultTxSpeed'; 2 | import { ChainId } from '~/core/types/chains'; 3 | import { GasSpeed } from '~/core/types/gas'; 4 | 5 | const shouldUseDefaultTxSpeed = (chainId: ChainId) => 6 | chainId === ChainId.mainnet || chainId === ChainId.polygon; 7 | 8 | export const useDefaultTxSpeed = ({ chainId }: { chainId: ChainId }) => { 9 | const { defaultTxSpeed: storeDefaultTxSpeed } = useDefaultTxSpeedStore(); 10 | 11 | return { 12 | defaultTxSpeed: shouldUseDefaultTxSpeed(chainId) 13 | ? storeDefaultTxSpeed 14 | : GasSpeed.NORMAL, 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useHomePromptsQueue.ts: -------------------------------------------------------------------------------- 1 | import { useHomePromptsQueueStore } from '~/core/state'; 2 | 3 | export const useHomePromptQueue = () => { 4 | const { queue, popQueue } = useHomePromptsQueueStore(); 5 | 6 | const nextInQueue = queue[0]; 7 | 8 | return { 9 | nextInQueue, 10 | popQueue, 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useIsFullScreen.ts: -------------------------------------------------------------------------------- 1 | import { isFullScreen } from '../utils/windows'; 2 | 3 | export function useIsFullScreen() { 4 | return isFullScreen; 5 | } 6 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useNativeAssetForNetwork.ts: -------------------------------------------------------------------------------- 1 | import { ETH_ADDRESS } from '~/core/references'; 2 | import { useNetworkStore } from '~/core/state/networks/networks'; 3 | import { UniqueId } from '~/core/types/assets'; 4 | import { ChainId } from '~/core/types/chains'; 5 | 6 | export const getNetworkNativeAssetUniqueId = ({ 7 | chainId = ChainId.mainnet, 8 | }: { 9 | chainId?: ChainId; 10 | }): UniqueId => { 11 | const nativeAssetAddress = 12 | useNetworkStore.getState().getChainsNativeAsset()[chainId]?.address || 13 | ETH_ADDRESS; 14 | return `${nativeAssetAddress}_${chainId}`; 15 | }; 16 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/usePendingTransactionWatcher.ts: -------------------------------------------------------------------------------- 1 | import { useCurrentAddressStore } from '~/core/state'; 2 | 3 | import { usePoll } from './usePoll'; 4 | import { useWatchPendingTransactions } from './useWatchPendingTransactions'; 5 | 6 | const PENDING_TRANSACTION_POLLING_INTERVAL = 5000; 7 | 8 | export function PendingTransactionWatcher() { 9 | const address = useCurrentAddressStore((s) => s.currentAddress); 10 | 11 | const { watchPendingTransactions } = useWatchPendingTransactions({ address }); 12 | usePoll(watchPendingTransactions, PENDING_TRANSACTION_POLLING_INTERVAL); 13 | 14 | return null; 15 | } 16 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/usePoll.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useLayoutEffect, useRef } from 'react'; 2 | 3 | export function usePoll(callback: () => void, delay: number) { 4 | const cbRef = useRef<() => void>(); 5 | 6 | useLayoutEffect(() => { 7 | cbRef.current = callback; 8 | }, [callback]); 9 | 10 | useEffect(() => { 11 | if (delay === null) return; 12 | const cb = () => cbRef.current?.(); 13 | const id = setInterval(cb, delay); 14 | return () => { 15 | clearInterval(id); 16 | }; 17 | }, [callback, delay]); 18 | } 19 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/usePress.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useRef, useState } from 'react'; 2 | 3 | export const usePress = (onPressed: () => void) => { 4 | const pressTimerRef = useRef(); 5 | const [pressed, setPressed] = useState(false); 6 | 7 | const startPress = useCallback(() => { 8 | setPressed(false); 9 | if (pressTimerRef.current) clearTimeout(pressTimerRef.current); 10 | pressTimerRef.current = setTimeout(() => { 11 | onPressed(); 12 | setPressed(true); 13 | }, 500); 14 | }, [onPressed]); 15 | 16 | const endPress = useCallback(() => { 17 | if (pressed) setPressed(false); 18 | if (pressTimerRef.current) clearTimeout(pressTimerRef.current); 19 | }, [pressed]); 20 | 21 | return { pressed, startPress, endPress }; 22 | }; 23 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/usePrevious.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | export default function usePrevious(value: T): T | undefined { 4 | const ref = useRef(); 5 | 6 | useEffect(() => { 7 | ref.current = value; 8 | }, [value]); 9 | 10 | return ref.current; 11 | } 12 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useScroll.ts: -------------------------------------------------------------------------------- 1 | import { useScroll as useMotionScroll } from 'framer-motion'; 2 | 3 | import { useContainerRef } from '~/design-system/components/AnimatedRoute/AnimatedRoute'; 4 | 5 | export const useScroll = (options?: Parameters[0]) => { 6 | const container = useContainerRef(); 7 | return useMotionScroll({ container, layoutEffect: false, ...options }); 8 | }; 9 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useSystemSpecificModifierKey.ts: -------------------------------------------------------------------------------- 1 | export const useSystemSpecificModifierKey = () => { 2 | const modifierKey = navigator.userAgent.includes('Mac') 3 | ? 'metaKey' 4 | : 'ctrlKey'; 5 | const modifierSymbol = navigator.userAgent.includes('Mac') ? '⌘' : 'Ctrl-'; 6 | return { modifierKey, modifierSymbol }; 7 | }; 8 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useTranslationContext.ts: -------------------------------------------------------------------------------- 1 | import { TranslateOptions } from 'i18n-js'; 2 | import { createContext, useCallback, useContext } from 'react'; 3 | 4 | import { i18n } from '~/core/languages'; 5 | 6 | const translationContext = createContext( 7 | undefined, 8 | ); 9 | 10 | export const TranslationContext = translationContext.Provider; 11 | 12 | export const useTranslationContext = (contextOverride?: TranslateOptions) => { 13 | const contextOptions = useContext(translationContext); 14 | 15 | return useCallback( 16 | (s: string | string[], options?: TranslateOptions | undefined) => 17 | i18n.t(s, { ...(contextOverride || contextOptions), ...options }), 18 | [contextOptions, contextOverride], 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useUserAsset.ts: -------------------------------------------------------------------------------- 1 | import { Address } from 'viem'; 2 | 3 | import { selectUserAssetWithUniqueId } from '~/core/resources/_selectors/assets'; 4 | import { useUserAssets } from '~/core/resources/assets'; 5 | import { useCurrentAddressStore, useCurrentCurrencyStore } from '~/core/state'; 6 | import { UniqueId } from '~/core/types/assets'; 7 | 8 | export function useUserAsset(uniqueId?: UniqueId, address?: Address) { 9 | const { currentAddress } = useCurrentAddressStore(); 10 | const { currentCurrency: currency } = useCurrentCurrencyStore(); 11 | return useUserAssets( 12 | { 13 | address: address || currentAddress, 14 | currency, 15 | }, 16 | { 17 | select: uniqueId ? selectUserAssetWithUniqueId(uniqueId) : undefined, 18 | enabled: !!uniqueId, 19 | }, 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useVirtualizedAssets.ts: -------------------------------------------------------------------------------- 1 | import { useVirtualizer } from '@tanstack/react-virtual'; 2 | import { useRef } from 'react'; 3 | 4 | import { 5 | ParsedAsset, 6 | ParsedSearchAsset, 7 | ParsedUserAsset, 8 | } from '~/core/types/assets'; 9 | import { SearchAsset } from '~/core/types/search'; 10 | 11 | export const useVirtualizedAssets = ({ 12 | assets, 13 | size, 14 | }: { 15 | assets?: 16 | | ParsedAsset[] 17 | | ParsedUserAsset[] 18 | | ParsedSearchAsset[] 19 | | SearchAsset[]; 20 | size?: number; 21 | }) => { 22 | const containerRef = useRef(null); 23 | 24 | const assetsRowVirtualizer = useVirtualizer({ 25 | count: assets?.length || 0, 26 | getScrollElement: () => containerRef.current, 27 | estimateSize: () => (size ? size : 52), 28 | overscan: 20, 29 | }); 30 | return { 31 | containerRef, 32 | assetsRowVirtualizer, 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useWalletName.ts: -------------------------------------------------------------------------------- 1 | import { Address } from 'viem'; 2 | import { useEnsName } from 'wagmi'; 3 | 4 | import { useWalletNamesStore } from '~/core/state/walletNames'; 5 | import { ChainId } from '~/core/types/chains'; 6 | import { truncateAddress } from '~/core/utils/address'; 7 | 8 | export const useWalletName = ({ address }: { address?: Address }) => { 9 | const { data: ensName } = useEnsName({ 10 | address, 11 | chainId: ChainId.mainnet, 12 | }); 13 | 14 | const { walletNames } = useWalletNamesStore(); 15 | 16 | if (!address) { 17 | return { 18 | displayName: undefined, 19 | showAddress: undefined, 20 | }; 21 | } 22 | 23 | const displayName = 24 | walletNames[address] || ensName || truncateAddress(address); 25 | const showAddress = walletNames[address] || ensName; 26 | 27 | return { 28 | displayName, 29 | showAddress, 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/entries/popup/hooks/useWalletsFromKeychain.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | import { KeychainWallet } from '~/core/types/keychainTypes'; 4 | 5 | import { getWallets } from '../handlers/wallet'; 6 | 7 | export const useWalletsFromKeychain = () => { 8 | const [walletsFromKeychain, setWalletsFromKeychain] = useState< 9 | KeychainWallet[] 10 | >([]); 11 | useEffect(() => { 12 | const fetchWallets = async () => { 13 | const walletsFromKeychain = await getWallets(); 14 | setWalletsFromKeychain(walletsFromKeychain); 15 | }; 16 | fetchWallets(); 17 | }, []); 18 | return { walletsFromKeychain }; 19 | }; 20 | -------------------------------------------------------------------------------- /src/entries/popup/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Rainbow Wallet 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/entries/popup/index.ts: -------------------------------------------------------------------------------- 1 | import './global.css'; 2 | 3 | import { createElement } from 'react'; 4 | import { createRoot } from 'react-dom/client'; 5 | 6 | import { 7 | syncNetworksStore, 8 | syncStores, 9 | } from '~/core/state/internal/syncStores'; 10 | import { initThemingLocal } from '~/design-system/styles/initThemingLocal'; 11 | 12 | import { App } from './App'; 13 | 14 | require('../../core/utils/lockdown'); 15 | 16 | initThemingLocal(); 17 | syncStores(); 18 | syncNetworksStore('popup'); 19 | 20 | if (process.env.IS_TESTING === 'true') { 21 | await import('../../../e2e/mockFetch').then((m) => m.mockFetch()); 22 | } 23 | 24 | const domContainer = document.querySelector('#app') as Element; 25 | const root = createRoot(domContainer); 26 | root.render(createElement(App)); 27 | -------------------------------------------------------------------------------- /src/entries/popup/layouts/MainLayout.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Box } from '~/design-system'; 4 | 5 | export function MainLayout({ 6 | className, 7 | children, 8 | style, 9 | }: { 10 | className?: string; 11 | children: React.ReactNode; 12 | style?: React.CSSProperties; 13 | }) { 14 | return ( 15 | 23 | {children} 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/entries/popup/pages/_playgrounds/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Default } from './default'; 4 | import { DesignSystem } from './ds'; 5 | 6 | export const PlaygroundComponents = { 7 | default: , 8 | ds: , 9 | }; 10 | -------------------------------------------------------------------------------- /src/entries/popup/pages/home/Activity/ActivityPill.css.ts: -------------------------------------------------------------------------------- 1 | import { keyframes, style } from '@vanilla-extract/css'; 2 | 3 | export const pendingDashLenght = 50; 4 | 5 | const line = keyframes({ 6 | '100%': { strokeDashoffset: pendingDashLenght }, 7 | }); 8 | 9 | export const pendingStyle = style([ 10 | { 11 | strokeDasharray: `${pendingDashLenght}px var(--activity-pill-pending-dashArray-gap)`, 12 | strokeDashoffset: `calc(-1 * var(--activity-pill-pending-dashArray-gap))`, 13 | animationName: line, 14 | animationDuration: '2.5s', 15 | animationTimingFunction: 'linear', 16 | animationIterationCount: 'infinite', 17 | }, 18 | ]); 19 | -------------------------------------------------------------------------------- /src/entries/popup/pages/home/Activity/NoActivity.tsx: -------------------------------------------------------------------------------- 1 | import { i18n } from '~/core/languages'; 2 | import { Box, Inset, Text } from '~/design-system'; 3 | 4 | export const NoActivity = () => { 5 | return ( 6 | 13 | 14 | 20 | {i18n.t('activity.empty_header')} 21 | 22 | 23 | 24 | 30 | {i18n.t('activity.empty_description')} 31 | 32 | 33 | 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /src/entries/popup/pages/home/Approvals/Approvals.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | export const childAStyle = style({ 4 | display: 'none', // Default non-hover state 5 | selectors: { 6 | [`.approval-row:hover &`]: { 7 | display: 'block', // Display when parent is hovered 8 | }, 9 | }, 10 | }); 11 | 12 | export const childBStyle = style({ 13 | display: 'block', // Default non-hover state 14 | selectors: { 15 | [`.approval-row:hover &`]: { 16 | display: 'none', // Hide when parent is hovered 17 | }, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /src/entries/popup/pages/home/NFTs/utils.ts: -------------------------------------------------------------------------------- 1 | import { UniqueAsset } from '~/core/types/nfts'; 2 | 3 | export const getOpenseaUrl = ({ 4 | nft, 5 | collectionPage, 6 | }: { 7 | nft?: UniqueAsset | null; 8 | collectionPage?: boolean; 9 | }) => { 10 | const networkUrlString = 11 | nft?.network === 'mainnet' ? 'ethereum' : nft?.network; 12 | const openseaNftUrl = `https://opensea.io/assets/${networkUrlString}/${nft?.asset_contract.address}/${nft?.id}`; 13 | const openseaCollectionUrl = `https://opensea.io/assets/${networkUrlString}/${nft?.asset_contract.address}`; 14 | return collectionPage ? openseaCollectionUrl : openseaNftUrl; 15 | }; 16 | 17 | export const getRaribleUrl = ({ nft }: { nft?: UniqueAsset | null }) => { 18 | return `https://rarible.com/token/${nft?.asset_contract.address}:${nft?.id}`; 19 | }; 20 | -------------------------------------------------------------------------------- /src/entries/popup/pages/home/PageHeader.css.ts: -------------------------------------------------------------------------------- 1 | import { boxStyles } from '~/design-system'; 2 | 3 | export const pageHeaderButtonStyles = { 4 | default: boxStyles({ 5 | background: 'surfaceSecondaryElevated', 6 | borderColor: 'buttonStroke', 7 | borderWidth: '1px', 8 | }), 9 | ghost: undefined, 10 | }; 11 | -------------------------------------------------------------------------------- /src/entries/popup/pages/home/Points/usePointsChallenge.tsx: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import { Address } from 'viem'; 3 | 4 | import { metadataClient } from '~/core/graphql'; 5 | import { createQueryKey } from '~/core/react-query'; 6 | 7 | export const usePointsChallenge = ({ 8 | address, 9 | referralCode, 10 | }: { 11 | address: Address; 12 | referralCode: string | undefined; 13 | }) => { 14 | return useQuery({ 15 | queryFn: () => { 16 | return metadataClient.getPointsOnboardChallenge({ 17 | address, 18 | referral: referralCode, 19 | }); 20 | }, 21 | queryKey: createQueryKey('points challenge', { 22 | address, 23 | referralCode, 24 | }), 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /src/entries/popup/pages/home/TokenMarkedHighlighter.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '~/design-system'; 2 | 3 | export function TokenMarkedHighlighter() { 4 | return ( 5 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src/entries/popup/pages/hw/walletList/walletList.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | export const accountIndexHoverContainerStyle = style([]); 4 | 5 | export const accountIndexHiddenHoverStyle = style([ 6 | { 7 | opacity: 0, 8 | width: 5, 9 | overflow: 'hidden', 10 | transition: 'all .5s cubic-bezier(0.175, 0.885, 0.32, 1.3)', 11 | selectors: { 12 | [`${accountIndexHoverContainerStyle}:hover &`]: { 13 | opacity: 1, 14 | width: 31, 15 | transition: 'all .5s cubic-bezier(0.175, 0.885, 0.32, 1.18)', 16 | }, 17 | }, 18 | }, 19 | ]); 20 | 21 | export const accountIndexHiddenHoverSiblingStyle = style([ 22 | { 23 | marginLeft: -5, 24 | selectors: { 25 | [`${accountIndexHoverContainerStyle}:hover &`]: { 26 | marginLeft: 0, 27 | }, 28 | }, 29 | }, 30 | ]); 31 | -------------------------------------------------------------------------------- /src/entries/popup/pages/importWallet/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { FullScreenContainer } from '../../components/FullScreen/FullScreenContainer'; 4 | import { ImportWallet as ImportWalletStep } from '../../components/ImportWallet/ImportWallet'; 5 | 6 | export function ImportWallet() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/entries/popup/pages/importWalletSelection/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { FullScreenContainer } from '../../components/FullScreen/FullScreenContainer'; 4 | import { ImportWalletNavbar } from '../../components/ImportWallet/ImportWalletNavbar'; 5 | import { ImportWalletSelection as ImportWalletSelectionStep } from '../../components/ImportWallet/ImportWalletSelection'; 6 | 7 | export function ImportWalletSelection() { 8 | return ( 9 | <> 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/entries/popup/pages/messages/OverflowGradient.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { backgroundColors } from '~/design-system/styles/designTokens'; 4 | 5 | export const overflowGradientDark = style([ 6 | { 7 | '::after': { 8 | content: '', 9 | position: 'absolute', 10 | bottom: 0, 11 | left: 0, 12 | right: 0, 13 | height: '38px', 14 | background: `linear-gradient(180deg, transparent 0%, ${backgroundColors.surfaceSecondaryElevated.dark.color} 100%)`, 15 | }, 16 | }, 17 | ]); 18 | 19 | export const overflowGradientLight = style([ 20 | { 21 | '::after': { 22 | content: '', 23 | position: 'absolute', 24 | bottom: 0, 25 | left: 0, 26 | right: 0, 27 | height: '38px', 28 | background: `linear-gradient(180deg, transparent 0%, ${backgroundColors.surfaceSecondaryElevated.light.color} 100%)`, 29 | }, 30 | }, 31 | ]); 32 | -------------------------------------------------------------------------------- /src/entries/popup/pages/rootHandler/RootHandler.tsx: -------------------------------------------------------------------------------- 1 | export function RootHandler() { 2 | return null; 3 | } 4 | -------------------------------------------------------------------------------- /src/entries/popup/pages/send/RowHighlightWrapper.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | import { useCurrentThemeStore } from '~/core/state/currentSettings/currentTheme'; 4 | import { Box } from '~/design-system'; 5 | 6 | import { 7 | addressToInputHighlightWrapperStyleDark, 8 | addressToInputHighlightWrapperStyleLight, 9 | } from './ToAddressInput.css'; 10 | 11 | export const RowHighlightWrapper = ({ children }: { children: ReactNode }) => { 12 | const { currentTheme } = useCurrentThemeStore(); 13 | return ( 14 | 22 | {children} 23 | 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/entries/popup/pages/send/ToAddressInput.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { boxStyles } from '~/design-system'; 4 | import { foregroundColors } from '~/design-system/styles/designTokens'; 5 | 6 | export const addressToInputHighlightWrapperStyleLight = style([ 7 | boxStyles({ 8 | borderRadius: '12px', 9 | }), 10 | { 11 | ':hover': { 12 | backgroundColor: foregroundColors.separatorTertiary.light, 13 | }, 14 | }, 15 | ]); 16 | 17 | export const addressToInputHighlightWrapperStyleDark = style([ 18 | boxStyles({ 19 | borderRadius: '12px', 20 | }), 21 | { 22 | ':hover': { 23 | backgroundColor: foregroundColors.separatorTertiary.dark, 24 | }, 25 | }, 26 | ]); 27 | -------------------------------------------------------------------------------- /src/entries/popup/pages/swap/SwapTokenInput.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | import { boxStyles } from '~/design-system'; 4 | import { foregroundColors } from '~/design-system/styles/designTokens'; 5 | 6 | export const swapTokenInputHighlightWrapperStyleLight = style([ 7 | boxStyles({ 8 | borderRadius: '12px', 9 | }), 10 | { 11 | ':hover': { 12 | backgroundColor: foregroundColors.separatorTertiary.light, 13 | }, 14 | }, 15 | ]); 16 | 17 | export const swapTokenInputHighlightWrapperStyleDark = style([ 18 | boxStyles({ 19 | borderRadius: '12px', 20 | }), 21 | { 22 | ':hover': { 23 | backgroundColor: foregroundColors.separatorTertiary.dark, 24 | }, 25 | }, 26 | ]); 27 | -------------------------------------------------------------------------------- /src/entries/popup/pages/swap/SwapTokenInput/TokenRow/RowHighlightWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | 3 | import { useCurrentThemeStore } from '~/core/state/currentSettings/currentTheme'; 4 | import { Box, Inset } from '~/design-system'; 5 | 6 | import { 7 | swapTokenInputHighlightWrapperStyleDark, 8 | swapTokenInputHighlightWrapperStyleLight, 9 | } from '../../SwapTokenInput.css'; 10 | 11 | export const RowHighlightWrapper = ({ children }: { children: ReactNode }) => { 12 | const { currentTheme } = useCurrentThemeStore(); 13 | return ( 14 | 15 | 23 | {children} 24 | 25 | 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /src/entries/popup/pages/swap/swapTimeEstimate.ts: -------------------------------------------------------------------------------- 1 | import { CrosschainQuote, Quote, QuoteError } from '@rainbow-me/swaps'; 2 | 3 | import { 4 | getCrossChainTimeEstimate, 5 | getQuoteServiceTime, 6 | } from '~/core/utils/swaps'; 7 | 8 | export interface SwapTimeEstimate { 9 | isLongWait: boolean; 10 | timeEstimate?: number; 11 | timeEstimateDisplay: string; 12 | } 13 | 14 | export function getSwapTimeEstimate( 15 | quote: Quote | CrosschainQuote | QuoteError | undefined, 16 | ) { 17 | if (!quote || 'error' in quote) return null; 18 | const serviceTime = getQuoteServiceTime({ quote }); 19 | if (!serviceTime) return null; 20 | const timeEstimate = getCrossChainTimeEstimate({ serviceTime }); 21 | return timeEstimate; 22 | } 23 | -------------------------------------------------------------------------------- /src/entries/popup/pages/swap/utils.ts: -------------------------------------------------------------------------------- 1 | import { Source } from '@rainbow-me/swaps'; 2 | 3 | import Logo0x from 'static/assets/aggregators/0x.png'; 4 | import Logo1Inch from 'static/assets/aggregators/1inch.png'; 5 | import LogoRainbow from 'static/assets/aggregators/rainbow.png'; 6 | import { i18n } from '~/core/languages'; 7 | 8 | export const aggregatorInfo = { 9 | auto: { logo: LogoRainbow, name: i18n.t('swap.aggregators.rainbow') }, 10 | [Source.Aggregator0x]: { logo: Logo0x, name: Source.Aggregator0x }, 11 | [Source.Aggregator1inch]: { logo: Logo1Inch, name: Source.Aggregator1inch }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/entries/popup/pages/walletReady/ReadyHotkeys/pressTransitions.css.ts: -------------------------------------------------------------------------------- 1 | import { style, styleVariants } from '@vanilla-extract/css'; 2 | 3 | const baseTransitions = style({ 4 | transition: 'opacity 0.2s ease-in-out, top 0.2s ease-in-out', 5 | transitionProperty: 'top', 6 | transitionDelay: '0.17s', 7 | }); 8 | 9 | export const activeTransitions = styleVariants({ 10 | pressed: [baseTransitions, { top: '2px', opacity: 1 }], 11 | 'not pressed': [baseTransitions, { top: 0, opacity: 0 }], 12 | }); 13 | 14 | export const inactiveTransitions = styleVariants({ 15 | pressed: [baseTransitions, { top: '2px', opacity: 0 }], 16 | 'not pressed': [baseTransitions, { top: 0, opacity: 1 }], 17 | }); 18 | -------------------------------------------------------------------------------- /src/entries/popup/pages/walletSwitcher/newImportWallet.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '~/design-system'; 2 | 3 | import { ImportWallet } from '../../components/ImportWallet/ImportWallet'; 4 | 5 | const NewImportWallet = () => { 6 | return ( 7 | 15 | 16 | 17 | ); 18 | }; 19 | 20 | export { NewImportWallet }; 21 | -------------------------------------------------------------------------------- /src/entries/popup/pages/walletSwitcher/newImportWalletSelection.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '~/design-system'; 2 | 3 | import { ImportWalletSelection } from '../../components/ImportWallet/ImportWalletSelection'; 4 | 5 | const NewImportWalletSelection = () => { 6 | return ( 7 | 15 | 16 | 17 | ); 18 | }; 19 | 20 | export { NewImportWalletSelection }; 21 | -------------------------------------------------------------------------------- /src/entries/popup/utils/activeElement.ts: -------------------------------------------------------------------------------- 1 | export const getActiveElement = () => document.activeElement; 2 | export const getActiveModal = () => 3 | document.querySelector('div[data-is-modally-presented]'); 4 | export const getExplainerSheet = () => 5 | document.querySelector('div[data-is-explainer-sheet]'); 6 | export const getInputIsFocused = () => { 7 | const tagName = getActiveElement()?.tagName || ''; 8 | return ['INPUT', 'TEXTAREA'].includes(tagName); 9 | }; 10 | export const radixIsActive = () => 11 | !!document.querySelector('div[data-radix-popper-content-wrapper]'); 12 | export const switchNetworkMenuIsActive = () => 13 | !!document.getElementById('switch-network-menu-selector'); 14 | export const appConnectionMenuIsActive = () => 15 | !!document.getElementById('app-connection-menu-selector-open'); 16 | export const appConnectionSwitchWalletsPromptIsActive = () => 17 | !!document.getElementById('app-connection-switch-wallets-prompt'); 18 | -------------------------------------------------------------------------------- /src/entries/popup/utils/emojiAvatarBackgroundColors.ts: -------------------------------------------------------------------------------- 1 | export const colors = [ 2 | '#FC5C54', 3 | '#FFD95A', 4 | '#E95D72', 5 | '#6A87C8', 6 | '#5FD0F3', 7 | '#75C06B', 8 | '#FFDD86', 9 | '#5FC6D4', 10 | '#FF949A', 11 | '#FF8024', 12 | '#9BA1A4', 13 | '#EC66FF', 14 | '#FF8CBC', 15 | '#FF9A23', 16 | '#C5DADB', 17 | '#A8CE63', 18 | '#71ABFF', 19 | '#FFE279', 20 | '#B6B1B6', 21 | '#FF6780', 22 | '#A575FF', 23 | '#4D82FF', 24 | '#FFB35A', 25 | ]; 26 | -------------------------------------------------------------------------------- /src/entries/popup/utils/isMobile.ts: -------------------------------------------------------------------------------- 1 | const userAgent = () => 2 | typeof navigator !== 'undefined' 3 | ? navigator.userAgent.toLocaleLowerCase() 4 | : ''; 5 | 6 | export const isAndroid = (ua = userAgent()) => ua.includes('android'); 7 | 8 | export const isSmallIOS = (ua = userAgent()) => 9 | ua.includes('iphone') || ua.includes('ipod'); 10 | 11 | export const isLargeIOS = (ua = userAgent()) => 12 | ua.includes('ipad') || (ua.includes('mac') && navigator.maxTouchPoints > 1); 13 | 14 | export const isIOS = (ua = userAgent()) => isSmallIOS(ua) || isLargeIOS(ua); 15 | 16 | export function isMobile() { 17 | const ua = userAgent(); 18 | if (!ua) return false; 19 | return isAndroid(ua) || isIOS(ua); 20 | } 21 | -------------------------------------------------------------------------------- /src/entries/popup/utils/mergeRefs.ts: -------------------------------------------------------------------------------- 1 | import type { ForwardedRef, RefCallback } from 'react'; 2 | 3 | export const mergeRefs = 4 | (...refs: Array>): RefCallback => 5 | (node) => { 6 | for (const ref of refs) { 7 | if (typeof ref === 'function') ref(node); 8 | else if (ref != null) ref.current = node; 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/entries/popup/utils/playSound.ts: -------------------------------------------------------------------------------- 1 | import CorrectSeedQuiz from 'static/assets/audio/correct_seed_quiz.mp3'; 2 | import IncorrectSeedQuiz from 'static/assets/audio/incorrect_seed_quiz.mp3'; 3 | import LockSound from 'static/assets/audio/ui_lock.mp3'; 4 | import UnlockSound from 'static/assets/audio/ui_unlock.mp3'; 5 | import SendSound from 'static/assets/audio/woosh.mp3'; 6 | import { useSoundStore } from '~/core/state/sound'; 7 | import { logger } from '~/logger'; 8 | 9 | const SOUNDS = { 10 | CorrectSeedQuiz, 11 | IncorrectSeedQuiz, 12 | LockSound, 13 | SendSound, 14 | UnlockSound, 15 | }; 16 | 17 | export default function playSound(sound: keyof typeof SOUNDS) { 18 | const { soundsEnabled } = useSoundStore.getState(); 19 | if (soundsEnabled) { 20 | new Audio(SOUNDS[sound]).play().catch((e) => { 21 | logger.warn(`Failed to play sound ${sound}`, e); 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/entries/popup/utils/pseudoRandomArrayItemFromString.ts: -------------------------------------------------------------------------------- 1 | const cache: { [key: string]: number } = {}; 2 | 3 | // For a given string, will always return same item from an array. 4 | export function pseudoRandomArrayItemFromString( 5 | string: string, 6 | array: T[], 7 | ): T | undefined { 8 | if (!string) return undefined; 9 | 10 | if (!cache[string]) { 11 | cache[string] = [...string] 12 | .map((char) => char.toLowerCase().charCodeAt(0)) 13 | .reduce((acc, v) => acc + v, 0); 14 | } 15 | 16 | const pseudoRandomIndex = cache[string] % array.length; 17 | 18 | return array[pseudoRandomIndex]; 19 | } 20 | -------------------------------------------------------------------------------- /src/entries/popup/utils/search.ts: -------------------------------------------------------------------------------- 1 | import { KeyOption, MatchSorterOptions, matchSorter } from 'match-sorter'; 2 | 3 | export const filterList = ( 4 | list: T[], 5 | searchQuery: string, 6 | keys?: KeyOption[], 7 | options?: MatchSorterOptions, 8 | ) => 9 | matchSorter(list, searchQuery, { 10 | keys, 11 | ...options, 12 | }); 13 | -------------------------------------------------------------------------------- /src/entries/popup/utils/tabIndexes.ts: -------------------------------------------------------------------------------- 1 | export const tabIndexes = { 2 | WALLET_HEADER_LEFT_BUTTON: 1, 3 | WALLET_HEADER_ACCOUNT_NAME: 2, 4 | WALLET_HEADER_RIGHT_BUTTON: 3, 5 | WALLET_HEADER_COPY_BUTTON: 4, 6 | WALLET_HEADER_SWAP_BUTTON: 5, 7 | WALLET_HEADER_SEND_BUTTON: 6, 8 | WALLET_HEADER_BUY_BUTTON: 7, 9 | WALLET_HEADER_TOKENS_TAB: 8, 10 | WALLET_HEADER_ACTIVITY_TAB: 9, 11 | }; 12 | -------------------------------------------------------------------------------- /src/entries/popup/utils/windows.ts: -------------------------------------------------------------------------------- 1 | import { POPUP_DIMENSIONS } from '~/core/utils/dimensions'; 2 | 3 | export const isExternalPopup = window.location.href.includes('tabId='); 4 | export const isFullScreen = 5 | window.innerHeight > POPUP_DIMENSIONS.height && 6 | window.innerWidth > POPUP_DIMENSIONS.width; 7 | -------------------------------------------------------------------------------- /src/entries/popup/utils/zIndexes.ts: -------------------------------------------------------------------------------- 1 | export const zIndexes = { 2 | NAVBAR: 1, 3 | PROMPT: 2, 4 | BOTTOM_SHEET: 4, 5 | CUSTOM_GAS_SHEET: 5, 6 | TAB_BAR: 3, 7 | ACTIVITY_DETAILS: 4, 8 | EXPLAINER_BOTTOM_SHEET: 6, 9 | CHILD_ROUTE: 4, 10 | FULL_SCREEN_WINDOW_STROKE: 7, 11 | COMMAND_K: 8, 12 | WINDOW_STROKE: 10, 13 | APP_CONNECTION_WALLET_SWITCHER: 11, 14 | SPEED_UP_CANCEL_PROMPT: 12, 15 | REVOKE_APPROVAL_SHEET: 13, 16 | TOAST: 14, 17 | ALERT: 15, 18 | }; 19 | -------------------------------------------------------------------------------- /src/logger/debugContext.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * *Do not import this directly.* Instead, use the shortcut reference `logger.DebugContext`. 3 | * 4 | * Add debug contexts here. Although convention typically calls for enums ito 5 | * be capitalized, for parity with the `LOG_DEBUG` env var, please use all 6 | * lowercase. 7 | */ 8 | export const DebugContext = { 9 | // e.g. swaps: 'swaps' 10 | } as const; 11 | -------------------------------------------------------------------------------- /static/_locales/ar/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow هو محفظة Ethereum ممتعة، بسيطة وآمنة تجعل من إدارة أصولك متعة", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/en_US/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow is a fun, simple, and secure Ethereum wallet that makes managing your assets a joy.", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/es_419/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow es una billetera Ethereum divertida, simple y segura que hace que la gestión de tus activos sea un placer", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/fr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow est un portefeuille Ethereum amusant, simple et sécurisé qui rend la gestion de vos actifs un plaisir", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/hi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow मजेदार, सरल, और सुरक्षित Ethereum वॉलेट है जो आपके संपत्ति का प्रबंधन आनंदमय बनाता है", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/id/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow adalah dompet Ethereum yang menyenangkan, sederhana, dan aman yang membuat pengelolaan aset Anda menjadi suatu kebahagiaan", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/ja/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbowは、資産の管理を楽しく、シンプルで、安全にするEthereumウォレットです。", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/ko/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow은 재미있고 간단하며 안전한 이더리움 지갑으로, 자산을 관리하는 것을 즐거움으로 만듭니다.", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/pt_BR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow é uma carteira Ethereum divertida, simples e segura que torna a gestão dos seus ativos um prazer.", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/ru/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow — это весёлый, простой и безопасный кошелёк Ethereum, который делает управление вашими активами радостью.", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/th/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow เป็นกระเป๋า Ethereum ที่สนุก ง่ายและปลอดภัย ทำให้การจัดการสินทรัพย์ของคุณเป็นสิ่งที่ยินดี", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/tr/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow, varlıklarınızı yönetmeyi bir zevk haline getiren eğlenceli, basit ve güvenli bir Ethereum cüzdanıdır.", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Rainbow", 4 | "description": "The name of the extension, displayed in the web store." 5 | }, 6 | "appShortName": { 7 | "message": "Rainbow", 8 | "description": "The short name of the extension, displayed in the toolbar." 9 | }, 10 | "appDescription": { 11 | "message": "Rainbow 是一个有趣、简单且安全的以太坊钱包,让您管理资产如获至宝", 12 | "description": "The description of the extension, displayed in the web store." 13 | } 14 | } -------------------------------------------------------------------------------- /static/assets/aggregators/0x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/aggregators/0x.png -------------------------------------------------------------------------------- /static/assets/aggregators/1inch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/aggregators/1inch.png -------------------------------------------------------------------------------- /static/assets/aggregators/rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/aggregators/rainbow.png -------------------------------------------------------------------------------- /static/assets/appConnectionImageMask.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /static/assets/appConnectionSheetImageMask.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /static/assets/appConnectionWalletItemImageMask.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /static/assets/appsConnectedImageMask.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /static/assets/audio/correct_seed_quiz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/audio/correct_seed_quiz.mp3 -------------------------------------------------------------------------------- /static/assets/audio/incorrect_seed_quiz.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/audio/incorrect_seed_quiz.mp3 -------------------------------------------------------------------------------- /static/assets/audio/ui_lock.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/audio/ui_lock.mp3 -------------------------------------------------------------------------------- /static/assets/audio/ui_unlock.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/audio/ui_unlock.mp3 -------------------------------------------------------------------------------- /static/assets/audio/woosh.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/audio/woosh.mp3 -------------------------------------------------------------------------------- /static/assets/bg/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/bg/noise.png -------------------------------------------------------------------------------- /static/assets/ethIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/ethIcon.png -------------------------------------------------------------------------------- /static/assets/hardhwareWalletAvatarImageMask.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /static/assets/hw/ledger-device-eth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/hw/ledger-device-eth.png -------------------------------------------------------------------------------- /static/assets/hw/ledger-device-unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/hw/ledger-device-unlock.png -------------------------------------------------------------------------------- /static/assets/hw/ledger-device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/hw/ledger-device.png -------------------------------------------------------------------------------- /static/assets/hw/ledger-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/hw/ledger-logo.png -------------------------------------------------------------------------------- /static/assets/hw/trezor-device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/hw/trezor-device.png -------------------------------------------------------------------------------- /static/assets/hw/trezor-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/hw/trezor-logo.png -------------------------------------------------------------------------------- /static/assets/masks/pending_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/masks/pending_mask.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_alt_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_alt_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_alt_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_alt_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_alt_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_alt_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_alt_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_alt_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_option_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_option_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_option_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_option_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_option_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_option_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_option_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_option_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_r_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_r_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_r_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_r_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_r_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_r_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_r_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_r_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_shift_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_shift_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_shift_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_shift_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_shift_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_shift_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/dark_shift_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/dark_shift_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_alt_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_alt_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_alt_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_alt_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_alt_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_alt_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_alt_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_alt_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_option_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_option_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_option_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_option_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_option_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_option_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_option_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_option_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_r_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_r_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_r_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_r_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_r_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_r_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_r_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_r_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_shift_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_shift_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_shift_pressed_bottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_shift_pressed_bottom@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_shift_pressed_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_shift_pressed_top@2x.png -------------------------------------------------------------------------------- /static/assets/onboarding/light_shift_top@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/onboarding/light_shift_top@2x.png -------------------------------------------------------------------------------- /static/assets/rainbow/light-rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/light-rainbow.png -------------------------------------------------------------------------------- /static/assets/rainbow/light-rainbow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/light-rainbow@2x.png -------------------------------------------------------------------------------- /static/assets/rainbow/neon-rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/neon-rainbow.png -------------------------------------------------------------------------------- /static/assets/rainbow/neon-rainbow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/neon-rainbow@2x.png -------------------------------------------------------------------------------- /static/assets/rainbow/og-rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/og-rainbow.png -------------------------------------------------------------------------------- /static/assets/rainbow/og-rainbow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/og-rainbow@2x.png -------------------------------------------------------------------------------- /static/assets/rainbow/pixel-rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/pixel-rainbow.png -------------------------------------------------------------------------------- /static/assets/rainbow/pixel-rainbow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/pixel-rainbow@2x.png -------------------------------------------------------------------------------- /static/assets/rainbow/rainbow-logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/rainbow-logo-light.png -------------------------------------------------------------------------------- /static/assets/rainbow/rainbow-logo-light@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/rainbow-logo-light@2x.png -------------------------------------------------------------------------------- /static/assets/rainbow/rainbow-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/rainbow-logo.png -------------------------------------------------------------------------------- /static/assets/rainbow/rainbow-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/rainbow-logo@2x.png -------------------------------------------------------------------------------- /static/assets/rainbow/white-rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/white-rainbow.png -------------------------------------------------------------------------------- /static/assets/rainbow/white-rainbow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/assets/rainbow/white-rainbow@2x.png -------------------------------------------------------------------------------- /static/images/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/images/icon-16.png -------------------------------------------------------------------------------- /static/images/icon-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/images/icon-16@2x.png -------------------------------------------------------------------------------- /static/images/icon-16@32x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/images/icon-16@32x.png -------------------------------------------------------------------------------- /static/images/icon-16@4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/images/icon-16@4x.png -------------------------------------------------------------------------------- /static/images/icon-16@8x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/images/icon-16@8x.png -------------------------------------------------------------------------------- /static/images/icon-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/images/icon-19.png -------------------------------------------------------------------------------- /static/images/icon-19@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rainbow-me/browser-extension/9f8c157cd25d04d8ccf4298217e505e7f2086ec3/static/images/icon-19@2x.png -------------------------------------------------------------------------------- /static/theming.js: -------------------------------------------------------------------------------- 1 | const theme = localStorage.getItem('theme'); 2 | if (theme === 'dark') { 3 | // The user prefers a dark color scheme 4 | document.documentElement.classList.add('dt'); 5 | } else { 6 | // The user prefers a light color scheme or no preference 7 | document.documentElement.classList.add('lt'); 8 | } 9 | -------------------------------------------------------------------------------- /static/themingBody.js: -------------------------------------------------------------------------------- 1 | const localTheme = localStorage.getItem('theme'); 2 | // theme is deined in theming.js as a variable that gets the value of the theme from localStorage 3 | const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); 4 | if (darkModeMediaQuery.matches) { 5 | // The user prefers a dark color scheme 6 | if (localTheme === 'dark') { 7 | document.body.classList.add('lt-dc', 'dt-dc'); 8 | } else { 9 | document.body?.classList.add('lt-lc', 'dt-lc'); 10 | } 11 | } else { 12 | // The user prefers a light color scheme or no preference 13 | if (localTheme === 'dark') { 14 | document.body?.classList.add('lt-dc', 'dt-lc'); 15 | } else { 16 | document.body?.classList.add('lt-lc', 'lt-lc'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /static/trezor-usb-permissions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TrezorConnect | Trezor 5 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /static/vendor/trezor-content-script.js: -------------------------------------------------------------------------------- 1 | /* 2 | Passing messages from background script to popup 3 | */ 4 | 5 | let port = chrome.runtime.connect({ name: 'trezor-connect' }); 6 | 7 | port.onMessage.addListener(message => { 8 | window.postMessage(message, window.location.origin); 9 | }); 10 | 11 | port.onDisconnect.addListener(() => { 12 | port = null; 13 | }); 14 | 15 | /* 16 | Passing messages from popup to background script 17 | */ 18 | 19 | window.addEventListener('message', event => { 20 | if (port && event.source === window && event.data) { 21 | port.postMessage({ data: event.data }); 22 | } 23 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "react-jsx", 17 | "baseUrl": ".", 18 | "paths": { 19 | "~/*": ["src/*"] 20 | }, 21 | }, 22 | "include": ["src", "e2e", ".env.d.ts"], 23 | "exclude": ["vitest.config.*", "e2e/serial/vitest.config.ts", "design-system/docs", "static/", "node_modules", "dist", "build"], 24 | } 25 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path'; 2 | 3 | import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; 4 | import dotenv from 'dotenv'; 5 | import { defineConfig } from 'vitest/config'; 6 | 7 | dotenv.config({ path: '.env' }); 8 | 9 | export default defineConfig({ 10 | plugins: [vanillaExtractPlugin()], 11 | test: { 12 | environment: 'happy-dom', 13 | include: ['src/**/*.test.(ts|tsx)'], 14 | testTimeout: 45_000, 15 | setupFiles: './src/test/setup.ts', 16 | watch: false, 17 | }, 18 | resolve: { 19 | alias: { 20 | '~': resolve(__dirname, './src'), 21 | static: resolve(__dirname, './static'), 22 | }, 23 | }, 24 | }); 25 | --------------------------------------------------------------------------------