├── .env.example
├── .env.production
├── .env.test
├── .eslintignore
├── .eslintrc.js
├── .git-blame-ignore-revs
├── .github
└── workflows
│ ├── cypress.yml
│ ├── dashboard-ci.yml
│ ├── dashboard-mainnet.yml
│ └── reusable-build-and-publish.yml
├── .gitignore
├── .husky
├── .gitignore
└── pre-commit
├── .lintstagedrc
├── .nvmrc
├── .prettierignore
├── .prettierrc.js
├── .storybook
├── main.js
└── preview.js
├── CODEOWNERS
├── Dockerfile.dev
├── README.md
├── SECURITY.md
├── craco.config.js
├── cypress.json
├── cypress
├── integration
│ └── App.spec.ts
├── support
│ ├── index.d.ts
│ └── index.ts
└── tsconfig.json
├── docker-compose.yml
├── manifest-ledger-live-app.json
├── multicall
├── .gitignore
├── README.md
├── contracts
│ └── Multicall.sol
├── deploy
│ └── 01_deploy_multicall.ts
├── hardhat.config.ts
├── package.json
├── tsconfig.json
└── yarn.lock
├── package.json
├── public
├── Metabanner_grid.jpg
├── favicon-T.png
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── scripts
├── rebuild_components_package.sh
└── start_dashboard.sh
├── src
├── App.tsx
├── __mocks__
│ ├── @ledgerhq
│ │ └── connect-kit-loader.js
│ ├── @starknet-react
│ │ ├── chains.js
│ │ └── core.js
│ ├── axios.js
│ ├── multiformats.js
│ ├── starknet.js
│ ├── starknetkit.js
│ ├── threshold-ts
│ │ └── index.ts
│ └── uint8arrays.js
├── __tests__
│ ├── compatibility
│ │ └── backwards-compatibility.test.tsx
│ └── setup
│ │ └── dependencies.test.ts
├── blocked-wallets
│ ├── README.md
│ └── blocklist.json
├── components
│ ├── AddToMetamaskButton
│ │ └── index.tsx
│ ├── AnnouncementBanner
│ │ ├── SecondaryAnnouncementBanner.tsx
│ │ └── index.tsx
│ ├── BundledRewardsAlert
│ │ └── index.tsx
│ ├── ButtonLink
│ │ └── index.tsx
│ ├── CopyToClipboard
│ │ └── index.tsx
│ ├── DetailedLinkListItem
│ │ └── index.tsx
│ ├── DotsLoadingIndicator
│ │ └── index.tsx
│ ├── FeedbackAnalyticsInfo.tsx
│ ├── FeedbackRoutesButton.tsx
│ ├── Forms
│ │ ├── Form.tsx
│ │ ├── FormikInput.tsx
│ │ ├── FormikTokenBalanceInput.tsx
│ │ ├── HelperErrorText.tsx
│ │ ├── TokenAmountForm.tsx
│ │ └── index.ts
│ ├── Identicon.tsx
│ ├── InfoBox
│ │ └── index.tsx
│ ├── Link
│ │ ├── SharedLinks.tsx
│ │ └── index.tsx
│ ├── MintDurationTiers
│ │ ├── MintDurationTiers.tsx
│ │ └── index.ts
│ ├── MintDurationWidget
│ │ ├── MintDurationWidget.tsx
│ │ └── index.ts
│ ├── Modal
│ │ ├── AnalyticsModal
│ │ │ └── index.tsx
│ │ ├── ClaimingRewards
│ │ │ ├── SuccessModal.tsx
│ │ │ └── index.tsx
│ │ ├── ConfirmStakingParams
│ │ │ ├── AdvancedParamsForm.tsx
│ │ │ └── index.tsx
│ │ ├── DeauthorizeApplicationModal
│ │ │ ├── InititateDeauthorization.tsx
│ │ │ └── index.tsx
│ │ ├── FeedbackSubmissionModal
│ │ │ └── index.tsx
│ │ ├── MapOperatorToStakingProviderConfirmationModal
│ │ │ └── index.tsx
│ │ ├── MapOperatorToStakingProviderModal
│ │ │ ├── MapOperatorToStakingProviderForm.tsx
│ │ │ └── index.tsx
│ │ ├── MapOperatorToStakingProviderSuccessModal
│ │ │ └── index.tsx
│ │ ├── ModalCloseButton.tsx
│ │ ├── ModalRoot.tsx
│ │ ├── NewAppsToAuthorizeModal
│ │ │ └── index.tsx
│ │ ├── NewStakerAuthorizeStakingApplicationModal
│ │ │ ├── NewStakerAuthorizationCard.tsx
│ │ │ ├── NewStakerAuthorizationForm.tsx
│ │ │ └── index.tsx
│ │ ├── SelectWalletModal
│ │ │ ├── ConnectCoinbase.tsx
│ │ │ ├── ConnectLedgerLive.tsx
│ │ │ ├── ConnectMetamask.tsx
│ │ │ ├── ConnectStarknet.tsx
│ │ │ ├── ConnectStarknetDirect.tsx
│ │ │ ├── ConnectSui.tsx
│ │ │ ├── ConnectTaho.tsx
│ │ │ ├── ConnectWalletConnect.tsx
│ │ │ ├── InitialSelection.tsx
│ │ │ ├── SuiWalletList.tsx
│ │ │ ├── __tests__
│ │ │ │ └── ConnectStarknet.test.tsx
│ │ │ ├── components
│ │ │ │ ├── AccountSuccessAlert.tsx
│ │ │ │ ├── CoinbaseStatusAlert.tsx
│ │ │ │ ├── IncorrectNetwork.tsx
│ │ │ │ ├── MetamaskNotInstalledAlert.tsx
│ │ │ │ ├── MetamaskStatusAlert.tsx
│ │ │ │ ├── WalletConnectStatusAlert.tsx
│ │ │ │ ├── WalletConnectionModalBase.tsx
│ │ │ │ ├── WalletInitializeAlert.tsx
│ │ │ │ ├── WalletRejectedAlert.tsx
│ │ │ │ └── index.ts
│ │ │ └── index.tsx
│ │ ├── StakingApplications
│ │ │ ├── AuthorizeStakingApps.tsx
│ │ │ ├── ConfirmDeauthorization.tsx
│ │ │ ├── DeauthorizationCompleted.tsx
│ │ │ ├── DeauthorizationInitiated.tsx
│ │ │ ├── IncreaseAuthorization.tsx
│ │ │ ├── IncreaseAuthorizationSuccess.tsx
│ │ │ ├── StakingApplicationsAuthorized.tsx
│ │ │ └── index.ts
│ │ ├── StakingChecklistModal
│ │ │ └── index.tsx
│ │ ├── StakingSuccessModal
│ │ │ ├── StakeSuccessOld.tsx
│ │ │ └── index.tsx
│ │ ├── SubmitStake
│ │ │ └── index.tsx
│ │ ├── TACoCommitmentModal
│ │ │ ├── SuccessModal.tsx
│ │ │ └── index.tsx
│ │ ├── TopupTModal
│ │ │ ├── LegacyTopUpModal.tsx
│ │ │ ├── TopUpTModal.tsx
│ │ │ └── index.tsx
│ │ ├── TopupTSuccessModal
│ │ │ └── index.tsx
│ │ ├── TransactionModal
│ │ │ ├── TransactionFailed.tsx
│ │ │ ├── TransactionIsPending.tsx
│ │ │ ├── TransactionIsWaitingForConfirmation.tsx
│ │ │ └── index.ts
│ │ ├── TransactionSuccessModal
│ │ │ └── index.tsx
│ │ ├── UnstakeSuccessModal
│ │ │ └── index.tsx
│ │ ├── UnstakeTModal
│ │ │ ├── DeauthorizeInfo.tsx
│ │ │ ├── Step1.tsx
│ │ │ ├── Step2.tsx
│ │ │ └── index.tsx
│ │ ├── UpgradeToTModal
│ │ │ ├── TransactionIdle.tsx
│ │ │ ├── UpgradeStats.tsx
│ │ │ ├── UpgradeSuccess.tsx
│ │ │ └── index.tsx
│ │ ├── index.ts
│ │ ├── tBTC
│ │ │ ├── GenerateNewDepositAddress.tsx
│ │ │ ├── InitiateUnminting.tsx
│ │ │ ├── NewTBTCApp.tsx
│ │ │ └── index.ts
│ │ └── withBaseModal.tsx
│ ├── Navbar
│ │ ├── AccountButton.tsx
│ │ ├── DarkModeSwitcher.tsx
│ │ ├── HamburgerButton.tsx
│ │ ├── NavbarComponent.tsx
│ │ ├── NetworkButton.tsx
│ │ ├── StarkNetNetworkButton.tsx
│ │ ├── SuiNetworkAlert.tsx
│ │ ├── TrmWalletScreeningAlert.tsx
│ │ ├── WalletConnectionAlert.tsx
│ │ ├── __tests__
│ │ │ ├── NavbarComponent.test.tsx
│ │ │ └── NavbarStarknetIntegration.test.tsx
│ │ └── index.tsx
│ ├── NotificationPill
│ │ └── index.tsx
│ ├── OutlineListItem.tsx
│ ├── QRCode
│ │ └── index.tsx
│ ├── Sidebar
│ │ ├── BrandIcon.tsx
│ │ ├── DesktopSidebar.tsx
│ │ ├── ExpanderIcon.tsx
│ │ ├── MobileSidebar.tsx
│ │ ├── NavItem.tsx
│ │ ├── SidebarFooter.tsx
│ │ └── index.tsx
│ ├── Spinner.tsx
│ ├── StakingApplicationForms
│ │ └── index.tsx
│ ├── StakingApplicationOperationIcon
│ │ └── index.tsx
│ ├── StakingProvidersList
│ │ └── index.tsx
│ ├── StakingStats
│ │ └── index.tsx
│ ├── StakingTimeline
│ │ └── index.tsx
│ ├── StarknetWalletStatus.tsx
│ ├── StatHighlightCard.tsx
│ ├── Step
│ │ └── index.tsx
│ ├── SubNavigationPills
│ │ └── index.tsx
│ ├── SubmitTxButton.tsx
│ ├── ThresholdSpinner
│ │ └── ThresholdSpinner.tsx
│ ├── Timeline
│ │ ├── Timeline.tsx
│ │ └── index.ts
│ ├── Toast
│ │ ├── Toast.tsx
│ │ └── index.ts
│ ├── TokenBalance.tsx
│ ├── TokenBalanceCard
│ │ ├── TokenBalanceCardTemplate.tsx
│ │ └── index.tsx
│ ├── TokenBalanceInput
│ │ └── index.tsx
│ ├── TooltipIcon.tsx
│ ├── TransactionDetails
│ │ └── index.tsx
│ ├── TransactionInfoTable
│ │ └── index.tsx
│ ├── Tree
│ │ ├── Tree.tsx
│ │ └── index.ts
│ ├── UnstakingFormLabel
│ │ └── index.tsx
│ ├── UpgradeCard
│ │ ├── UpgradeCardTemplate.tsx
│ │ └── index.tsx
│ ├── UpgradeIconGroup.tsx
│ ├── ViewInBlockExplorer.tsx
│ ├── __tests__
│ │ └── StarknetWalletStatus.test.tsx
│ ├── tBTC
│ │ ├── BridgeActivity.tsx
│ │ ├── BridgeProcessIndicator.tsx
│ │ ├── ExternalPool.tsx
│ │ ├── Links.tsx
│ │ ├── RecentDeposits.tsx
│ │ ├── SendBitcoinsToDepositAddressForm.tsx
│ │ ├── Stats.tsx
│ │ ├── TakeNoteList.tsx
│ │ ├── index.ts
│ │ └── tBTCText.tsx
│ ├── withOnlyConnectedWallet.tsx
│ └── withWalletConnection.tsx
├── config
│ ├── starknet.ts
│ └── starknetRetry.ts
├── constants
│ ├── featureFlags.ts
│ ├── index.ts
│ ├── stakingBonus.ts
│ ├── vendingMachine.ts
│ └── web3.ts
├── contexts
│ ├── LedgerLiveAppContext.tsx
│ ├── StakeCardContext.tsx
│ ├── StarknetWalletProvider.tsx
│ ├── SuiWalletProvider.tsx
│ ├── ThresholdContext.tsx
│ ├── TokenContext.tsx
│ ├── TransportProvider.tsx
│ └── __tests__
│ │ └── StarknetWalletProvider.test.tsx
├── declaration.d.ts
├── enums
│ ├── __tests__
│ │ └── web3.test.ts
│ ├── api.ts
│ ├── env.ts
│ ├── externalHref.ts
│ ├── index.ts
│ ├── modal.ts
│ ├── pool.ts
│ ├── staking.ts
│ ├── token.ts
│ ├── transactionType.ts
│ └── web3.ts
├── hooks
│ ├── __mocks__
│ │ └── useStarknetConnection.ts
│ ├── __tests__
│ │ ├── useFetchTvl.test.tsx
│ │ ├── useLocalStorage.test.ts
│ │ ├── useNonEVMConnection.test.ts
│ │ ├── useStarknetConnection.test.ts
│ │ ├── useTConvertedAmount.test.ts
│ │ └── useTExchangeRate.test.ts
│ ├── google-tag-manager
│ │ ├── index.ts
│ │ └── useGoogleTagManager.ts
│ ├── ledger-live-app
│ │ ├── index.ts
│ │ ├── useRequestBitcoinAccount.ts
│ │ ├── useRequestEthereumAccount.ts
│ │ └── useSendBitcoinTransaction.ts
│ ├── posthog
│ │ ├── index.ts
│ │ ├── useCapture.ts
│ │ ├── useCapturePageview.ts
│ │ ├── useCaptureWalletConnectedEvent.ts
│ │ ├── useIdentify.ts
│ │ └── usePosthog.ts
│ ├── sentry
│ │ ├── index.ts
│ │ ├── useCaptureMessage.ts
│ │ └── useSentry.ts
│ ├── staking-applications
│ │ ├── index.ts
│ │ ├── useAuthorizeMultipleAppsTransaction.ts
│ │ ├── useBondOperatorTransaction.ts
│ │ ├── useConfirmDeauthorizationTransaction.ts
│ │ ├── useIncreaseAuthorizationTransaction.ts
│ │ ├── useInitiateDeauthorization.ts
│ │ ├── useRegisterMultipleOperatorsTransaction.ts
│ │ ├── useRegisterOperatorTransaction.ts
│ │ ├── useStakingAppContract.ts
│ │ ├── useStakingAppDataByStakingProvider.ts
│ │ ├── useStakingAppMinAuthorizationAmount.ts
│ │ ├── useStakingAppParameters.ts
│ │ ├── useStakingApplicationAddress.ts
│ │ ├── useStakingApplicationDecreaseDelay.ts
│ │ ├── useStakingApplicationState.ts
│ │ ├── useSubscribeToAuthorizationDecreaseApprovedEvent.ts
│ │ ├── useSubscribeToAuthorizationDecreaseRequestedEvent.ts
│ │ ├── useSubscribeToAuthorizationIncreasedEvent.ts
│ │ ├── useSubscribeToOperatorRegisteredEvent.ts
│ │ ├── useSubscribeToOperatorStatusUpdatedEvent.ts
│ │ └── useUpdateOperatorStatus.tsx
│ ├── store
│ │ ├── index.ts
│ │ ├── useAppDispatch.ts
│ │ └── useAppSelector.ts
│ ├── tbtc
│ │ ├── __tests__
│ │ │ └── useStarknetTBTCBalance.test.ts
│ │ ├── index.ts
│ │ ├── useBridgeContract.ts
│ │ ├── useCheckDepositExpirationTime.ts
│ │ ├── useDepositTelemetry.ts
│ │ ├── useFetchDepositDetails.ts
│ │ ├── useFetchRecentDeposits.ts
│ │ ├── useFetchRedemptionDetails.ts
│ │ ├── useFetchTBTCFees.ts
│ │ ├── useFetchTBTCMetrics.ts
│ │ ├── useFindRedemptionInBitcoinTx.ts
│ │ ├── useRedemptionEstimatedFees.ts
│ │ ├── useRemoveDepositData.ts
│ │ ├── useRequestRedemption.ts
│ │ ├── useRevealDepositTransaction.ts
│ │ ├── useStarknetTBTCBalance.ts
│ │ ├── useSubscribeToOptimisticMintingFinalizedEvent.ts
│ │ ├── useSubscribeToOptimisticMintingRequestedEvent.ts
│ │ ├── useSubscribeToRedemptionRequestedEvent.ts
│ │ ├── useSubscribeToRedemptionsCompletedEvent.ts
│ │ ├── useSubsribeToDepositRevealedEvent.ts
│ │ ├── useTBTCDepositDataFromLocalStorage.ts
│ │ └── useTBTCVaultContract.ts
│ ├── useAddErc20ToMetamask.ts
│ ├── useAnalytics.ts
│ ├── useChakraBreakpoint.ts
│ ├── useCheckBonusEligibility.ts
│ ├── useConnectWallet.ts
│ ├── useDetectIfEmbed.ts
│ ├── useDocumentTitle.ts
│ ├── useETHData.ts
│ ├── useFetchExternalPoolData.ts
│ ├── useFetchOwnerStakes.ts
│ ├── useFetchStakingRewards.ts
│ ├── useFetchTvl.ts
│ ├── useIsActive.ts
│ ├── useIsEmbed.ts
│ ├── useLocalStorage.ts
│ ├── useMinStakeAmount.ts
│ ├── useModal.ts
│ ├── useNextRewardsDropDate.ts
│ ├── useNonEVMConnection.ts
│ ├── useSaveConnectedAddressToStore.ts
│ ├── useSidebar.ts
│ ├── useStakeCardContext.ts
│ ├── useStakingState.ts
│ ├── useStarknetConnection.ts
│ ├── useSubscribeToStakedEvent.ts
│ ├── useSubscribeToToppedUpEvent.ts
│ ├── useSubscribeToUnstakedEvent.ts
│ ├── useTBTCBridgeContractAddress.ts
│ ├── useTBTCTerms.ts
│ ├── useTBTCTokenAddress.ts
│ ├── useTConvertedAmount.ts
│ ├── useTExchangeRate.ts
│ ├── useTbtcState.ts
│ ├── useToken.ts
│ ├── useTokenBalance.ts
│ ├── useTokenState.ts
│ ├── useTokensBalanceCall.ts
│ ├── useTransaction.ts
│ └── useUpgradeHref.ts
├── index.tsx
├── merkle-drop
│ └── rewards.json
├── networks
│ ├── README.md
│ ├── constants
│ │ └── networks.ts
│ ├── enums
│ │ └── networks.ts
│ ├── hooks
│ │ └── useConnectedOrDefaultEthereumChainId.ts
│ ├── types
│ │ └── networks.ts
│ └── utils
│ │ ├── __tests__
│ │ └── getChainIdToNetworkName.test.ts
│ │ ├── chainId.ts
│ │ ├── connectedNetwork.ts
│ │ ├── createExplorerLink.ts
│ │ ├── getEthereumNetworkNameFromChainId.ts
│ │ ├── getMainnetOrTestnetChainId.ts
│ │ ├── getRpcUrl.ts
│ │ ├── index.ts
│ │ ├── mappings.ts
│ │ ├── networks.ts
│ │ └── networksAlchemyConfig.ts
├── pages
│ ├── Feedback
│ │ ├── BugReport
│ │ │ └── index.tsx
│ │ ├── Settings
│ │ │ └── index.tsx
│ │ ├── Suggestions
│ │ │ └── index.tsx
│ │ ├── UsabilitySurvey
│ │ │ └── index.tsx
│ │ └── index.tsx
│ ├── Overview
│ │ ├── AnalyticsBanner.tsx
│ │ ├── Network
│ │ │ ├── CardTemplate.tsx
│ │ │ ├── StakingOverview.tsx
│ │ │ ├── index.tsx
│ │ │ ├── tBTCBridgeStats.tsx
│ │ │ └── tBTCUserStats.tsx
│ │ └── index.tsx
│ ├── PageLayout.tsx
│ ├── Staking
│ │ ├── AuthorizeStakingApps
│ │ │ ├── AuthorizeApplicationsCardCheckbox
│ │ │ │ ├── AppAuthorizationInfo.tsx
│ │ │ │ └── index.tsx
│ │ │ └── index.tsx
│ │ ├── HowItWorks
│ │ │ ├── StakingOverview
│ │ │ │ ├── AboutAddressesCard.tsx
│ │ │ │ ├── AuthorizingApplicationsCard.tsx
│ │ │ │ ├── LegacyStakesCard.tsx
│ │ │ │ ├── NewTStakesCard.tsx
│ │ │ │ ├── StakingActionsCard.tsx
│ │ │ │ ├── ThresholdStakesCard.tsx
│ │ │ │ └── index.tsx
│ │ │ └── index.tsx
│ │ ├── NewStakeCard.tsx
│ │ ├── OperatorAddressMappingCard.tsx
│ │ ├── RewardsCard.tsx
│ │ ├── StakeCard
│ │ │ ├── Header
│ │ │ │ ├── HeaderTitle.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── StakeAddressInfo
│ │ │ │ └── index.tsx
│ │ │ ├── StakeApplications
│ │ │ │ ├── AuthorizeApplicationRow.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── StakeBalance
│ │ │ │ ├── LegacyStakeBalances
│ │ │ │ │ ├── BalanceTreeItem.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── StakeRewards
│ │ │ │ └── index.tsx
│ │ │ └── index.tsx
│ │ ├── StakeDetailsPage
│ │ │ ├── NodeStatusLabel.tsx
│ │ │ ├── StakeDetailRow.tsx
│ │ │ └── index.tsx
│ │ ├── StakedPortfolioCard.tsx
│ │ └── index.tsx
│ ├── Upgrade
│ │ ├── UpgradeKEEP.tsx
│ │ ├── UpgradeNU.tsx
│ │ ├── UpgradeToken.tsx
│ │ └── index.tsx
│ ├── index.ts
│ └── tBTC
│ │ ├── Bridge
│ │ ├── BridgeActivityCard
│ │ │ └── index.tsx
│ │ ├── BridgeLayout.tsx
│ │ ├── DepositDetails.tsx
│ │ ├── Mint.tsx
│ │ ├── MintUnmintNav.tsx
│ │ ├── Minting
│ │ │ ├── InitiateMinting.tsx
│ │ │ ├── MakeDeposit.tsx
│ │ │ ├── MintingFlowRouter.tsx
│ │ │ ├── MintingSuccess.tsx
│ │ │ ├── MintingTimeline.tsx
│ │ │ ├── ProvideData.tsx
│ │ │ └── __tests__
│ │ │ │ ├── InitiateMinting.StarkNet.test.tsx
│ │ │ │ ├── InitiateMinting.test.tsx
│ │ │ │ └── ProvideData.test.tsx
│ │ ├── ResumeDeposit.tsx
│ │ ├── TbtcBalanceCard.tsx
│ │ ├── Unmint.tsx
│ │ ├── UnmintDetails.tsx
│ │ ├── UnmintingCard
│ │ │ └── index.tsx
│ │ ├── __tests__
│ │ │ ├── DepositDetails.StarkNet.test.tsx
│ │ │ ├── DepositDetails.test.tsx
│ │ │ └── TbtcBalanceCard.test.tsx
│ │ ├── components
│ │ │ ├── BridgeProcessCardSubTitle.tsx
│ │ │ ├── BridgeProcessCardTitle.tsx
│ │ │ ├── BridgeProcessDetailsCard.tsx
│ │ │ ├── BridgeProcessDetailsIcons.tsx
│ │ │ ├── BridgeProcessDetailsPageSkeleton.tsx
│ │ │ ├── BridgeProcessEmptyState.tsx
│ │ │ ├── BridgeProcessResource.tsx
│ │ │ ├── BridgeProcessStep.tsx
│ │ │ ├── DepositDetailsStep.tsx
│ │ │ ├── DepositDetailsStepIcons.tsx
│ │ │ ├── MintingTransactionDetails.tsx
│ │ │ ├── StarkNetErrorState.tsx
│ │ │ ├── StarkNetLoadingState.tsx
│ │ │ ├── TbtcFees.tsx
│ │ │ ├── TimelineItem.tsx
│ │ │ └── __tests__
│ │ │ │ └── MintingTransactionDetails.test.tsx
│ │ └── index.tsx
│ │ ├── Explorer
│ │ └── index.tsx
│ │ ├── HowItWorks
│ │ ├── AuditsCard.tsx
│ │ ├── Banner.tsx
│ │ ├── ContractsCard.tsx
│ │ ├── JSONFileCard.tsx
│ │ ├── MintingTimelineCard.tsx
│ │ ├── TbtcBridgeCard.tsx
│ │ └── index.tsx
│ │ └── index.tsx
├── posthog
│ └── index.ts
├── react-app-env.d.ts
├── sentry
│ └── index.ts
├── setupTests.js
├── static
│ ├── icons
│ │ ├── Arbitrum.tsx
│ │ ├── Argent.tsx
│ │ ├── Base.tsx
│ │ ├── CoinbaseWallet.tsx
│ │ ├── EthereumDark.tsx
│ │ ├── EthereumLight.tsx
│ │ ├── IoHomeOutlineSharp.tsx
│ │ ├── KeepCircleBrand.tsx
│ │ ├── KeepLight.tsx
│ │ ├── LedgerDark.tsx
│ │ ├── LedgerLight.tsx
│ │ ├── MetaMask.tsx
│ │ ├── NuCircleBrand.tsx
│ │ ├── NuLight.tsx
│ │ ├── Starknet.tsx
│ │ ├── Sui.tsx
│ │ ├── Taho.tsx
│ │ ├── ThresholdCircleBrand.tsx
│ │ ├── ThresholdPurple.tsx
│ │ ├── ThresholdWhite.tsx
│ │ ├── TransactionError.tsx
│ │ ├── Ttoken.tsx
│ │ ├── WalletConect.tsx
│ │ ├── __tests__
│ │ │ └── StarknetIcons.test.tsx
│ │ ├── tBTCFill.tsx
│ │ ├── tBTCFillBlack.tsx
│ │ ├── tBTCOutline.tsx
│ │ └── tokenIconMap.ts
│ └── images
│ │ ├── AnalyticsIllustration.png
│ │ ├── AnalyticsIllustrationDark.png
│ │ ├── AuthorizingApplicationsIllustrationDark.png
│ │ ├── AuthorizingApplicationsIllustrationLight.png
│ │ ├── DiagonalArrowDark.png
│ │ ├── DiagonalArrowLight.png
│ │ ├── DiagonalPillDark.png
│ │ ├── DiagonalPillLight.png
│ │ ├── LearnAboutStakingIllustration.png
│ │ ├── ListIconArrowsDark.png
│ │ ├── ListIconArrowsLight.png
│ │ ├── ListIconStarDark.png
│ │ ├── ListIconStarLight.png
│ │ ├── ListIconStockDark.png
│ │ ├── ListIconStockLight.png
│ │ ├── MetaMask-Fox.png
│ │ ├── RandomBeaconDecrease.png
│ │ ├── RandomBeaconIncrease.png
│ │ ├── StakingApplicationsIllustrationDark.png
│ │ ├── StakingApplicationsIllustrationLight.png
│ │ ├── StakingHowItWorksIllustrationDark.png
│ │ ├── StakingHowItWorksIllustrationLight.png
│ │ ├── SunglassesDark.png
│ │ ├── SunglassesLight.png
│ │ ├── TACoDecrease.png
│ │ ├── TACoIncrease.png
│ │ ├── TBTCCurvePool.svg
│ │ ├── TBTC_WBTC_SBTC_pool.svg
│ │ ├── TbtcDecrease.png
│ │ ├── TbtcIncrease.png
│ │ ├── ThresholdBrandFull.svg
│ │ ├── ThresholdBrandFullWhite.svg
│ │ ├── bitcoin.svg
│ │ ├── code-slash.svg
│ │ ├── deauthorize-tbtc.svg
│ │ ├── increase-auth.svg
│ │ ├── minting-completed-card-bg.png
│ │ ├── minting-step-2.svg
│ │ ├── minting-step-3.svg
│ │ ├── preAppIllustrationDark.png
│ │ ├── preAppIllustrationLight.png
│ │ ├── randomBeaconAppIllustrationDark.png
│ │ ├── randomBeaconAppIllustrationLight.png
│ │ ├── stakingProviders
│ │ ├── BoarLogo.png
│ │ ├── ColossusLogo.png
│ │ ├── DelightLogo.svg
│ │ ├── InfStonesLogo.png
│ │ ├── P2PValidatorLogo.png
│ │ └── StakedLogo.png
│ │ ├── tBTC-bridge-no-history-dark.svg
│ │ ├── tBTC-bridge-no-history-light.svg
│ │ ├── tBTC-explorer-bg.svg
│ │ ├── tBTC.svg
│ │ ├── tBTCAppBanner.svg
│ │ ├── tBTCAppBannerWithGrid.svg
│ │ ├── tbtc-json-file.png
│ │ ├── tbtc-success.png
│ │ ├── tbtcAppIllustrationDark.svg
│ │ ├── tbtcAppIllustrationLight.svg
│ │ ├── tbtcMintingStep1.svg
│ │ ├── thresholdWordMark.svg
│ │ ├── unminting-empty-state-dark.svg
│ │ ├── unminting-empty-state.svg
│ │ └── upgrade-to-t.svg
├── store
│ ├── account
│ │ ├── effects.ts
│ │ ├── index.ts
│ │ ├── selectors.ts
│ │ └── slice.ts
│ ├── eth
│ │ ├── ethSlice.ts
│ │ └── index.ts
│ ├── index.ts
│ ├── listener.ts
│ ├── modal
│ │ ├── index.ts
│ │ └── modalSlice.ts
│ ├── rewards
│ │ ├── index.ts
│ │ ├── rewardsSlice.ts
│ │ └── selectors.ts
│ ├── sidebar
│ │ ├── index.ts
│ │ └── sidebarSlice.ts
│ ├── staking-applications
│ │ ├── effects.ts
│ │ ├── index.ts
│ │ ├── selectors.ts
│ │ └── slice.ts
│ ├── staking
│ │ ├── effects.ts
│ │ ├── index.ts
│ │ ├── selectors.ts
│ │ └── stakingSlice.ts
│ ├── tbtc
│ │ ├── effects.ts
│ │ ├── index.ts
│ │ ├── selectors.ts
│ │ └── tbtcSlice.ts
│ ├── tokens
│ │ ├── index.ts
│ │ └── tokenSlice.ts
│ └── transactions
│ │ ├── index.ts
│ │ └── transactionSlice.ts
├── tbtc
│ └── mock-bitcoin-client.ts
├── test-helpers
│ ├── renderWithProviders.tsx
│ ├── renderWithRedux.tsx
│ └── renderWithRouter.tsx
├── test
│ ├── __tests__
│ │ └── starknet-test-utils.test.tsx
│ └── starknet-test-utils.tsx
├── theme
│ ├── AnnouncementBanner.ts
│ ├── Badge.ts
│ ├── Checkbox.ts
│ ├── DetailedLinkListItem.ts
│ ├── DotsLoadingIndicator.ts
│ ├── InfoBox.ts
│ ├── NotificationPill.ts
│ ├── Radio.ts
│ ├── SecondaryAnnouncementBanner.ts
│ ├── Tabs.ts
│ ├── Timeline.ts
│ ├── Tooltip.ts
│ ├── Tree.ts
│ ├── fonts.ts
│ └── index.ts
├── threshold-ts
│ ├── __tests__
│ │ └── starknet-integration.test.ts
│ ├── applications
│ │ ├── __tests__
│ │ │ └── application.test.ts
│ │ └── index.ts
│ ├── index.ts
│ ├── mas
│ │ ├── __test__
│ │ │ └── mas.test.ts
│ │ └── index.ts
│ ├── multicall
│ │ ├── __test__
│ │ │ └── multicall.test.ts
│ │ └── index.ts
│ ├── staking
│ │ ├── __test__
│ │ │ └── staking.test.ts
│ │ ├── dapp-development-sepolia-artifacts
│ │ │ ├── LegacyKeepStaking.json
│ │ │ ├── NuCypherStakingEscrow.json
│ │ │ └── TokenStaking.json
│ │ ├── index.ts
│ │ ├── mainnet-artifacts
│ │ │ ├── LegacyKeepStaking.json
│ │ │ ├── NuCypherStakingEscrow.json
│ │ │ └── TokenStaking.json
│ │ └── sepolia-artifacts
│ │ │ ├── LegacyKeepStaking.json
│ │ │ ├── NuCypherStakingEscrow.json
│ │ │ └── TokenStaking.json
│ ├── tbtc
│ │ ├── __test__
│ │ │ └── tbtc.test.ts
│ │ ├── dapp-development-sepolia-artifacts
│ │ │ ├── Bridge.json
│ │ │ ├── RandomBeacon.json
│ │ │ ├── TBTC.json
│ │ │ ├── TBTCVault.json
│ │ │ └── WalletRegistry.json
│ │ ├── index.ts
│ │ ├── mainnet-artifacts
│ │ │ ├── ArbitrumL1BitcoinDepositor.json
│ │ │ ├── BaseL1BitcoinDepositor.json
│ │ │ ├── RandomBeacon.json
│ │ │ └── StarkNetBitcoinDepositor.json
│ │ └── sepolia-artifacts
│ │ │ ├── ArbitrumL1BitcoinDepositor.json
│ │ │ ├── BaseL1BitcoinDepositor.json
│ │ │ ├── RandomBeacon.json
│ │ │ └── StarkNetBitcoinDepositor.json
│ ├── tokens
│ │ ├── dapp-development-sepolia-artifacts
│ │ │ └── NuCypherToken.json
│ │ ├── mainnet-artifacts
│ │ │ └── NuCypherToken.json
│ │ └── sepolia-artifacts
│ │ │ └── NuCypherToken.json
│ ├── types
│ │ ├── __tests__
│ │ │ └── types.test.ts
│ │ └── index.ts
│ ├── utils
│ │ ├── address.ts
│ │ ├── bitcoin.ts
│ │ ├── chain.ts
│ │ ├── constants.ts
│ │ ├── contract.ts
│ │ ├── index.ts
│ │ ├── math.ts
│ │ └── transaction.ts
│ └── vending-machine
│ │ ├── __tests__
│ │ └── vending-machine.test.ts
│ │ ├── dapp-development-sepolia-artifacts
│ │ ├── VendingMachineKeep.json
│ │ └── VendingMachineNuCypher.json
│ │ ├── index.ts
│ │ ├── mainnet-artifacts
│ │ ├── VendingMachineKeep.json
│ │ └── VendingMachineNuCypher.json
│ │ └── sepolia-artifacts
│ │ ├── VendingMachineKeep.json
│ │ └── VendingMachineNuCypher.json
├── types
│ ├── array.ts
│ ├── chain.ts
│ ├── eth.ts
│ ├── index.ts
│ ├── modal.ts
│ ├── page.ts
│ ├── posthog.ts
│ ├── rewards.ts
│ ├── sidebar.ts
│ ├── staking-applications.ts
│ ├── staking.ts
│ ├── starknet.ts
│ ├── state.ts
│ ├── tbtc.ts
│ ├── token.ts
│ ├── transaction.ts
│ ├── trm.ts
│ └── wallet.ts
├── utils
│ ├── __tests__
│ │ ├── formatTokenAmount.test.ts
│ │ ├── getStakingAppLabel.test.ts
│ │ ├── shortenAddress.test.ts
│ │ ├── tbtcStarknetHelpers.test.ts
│ │ └── validateUserWalletAddress.test.ts
│ ├── crypto.ts
│ ├── curveAPI.ts
│ ├── date.ts
│ ├── exchangeAPI.ts
│ ├── formatAmount.ts
│ ├── forms.ts
│ ├── getContract.ts
│ ├── getDefaultBitcoinCredentials.ts
│ ├── getEnvVariable.ts
│ ├── getLedgerLiveAppEthereumSigner.ts
│ ├── getRangeSign.ts
│ ├── getStakeTitle.ts
│ ├── getStakingAppLabel.ts
│ ├── getThresholdLib.ts
│ ├── getUsdBalance.ts
│ ├── helpers.ts
│ ├── index.ts
│ ├── isWalletRejectionError.ts
│ ├── ledger.ts
│ ├── percentage.ts
│ ├── safeBigNumber.ts
│ ├── setTimeout.ts
│ ├── shortenAddress.ts
│ ├── stakingBonus.ts
│ ├── starknetErrorHandler.ts
│ ├── subgraphAPI.ts
│ ├── tBTC.ts
│ ├── tbtcLocalStorageData.ts
│ ├── tbtcStarknetHelpers.ts
│ ├── trmAPI.ts
│ └── verifyDepositAddress.ts
└── web3
│ ├── abi
│ ├── CumulativeMerkleDrop.json
│ ├── ERC20.json
│ ├── SimplePreApplication.json
│ └── TokenStaking.json
│ ├── connectors
│ ├── coinbaseWallet.ts
│ ├── index.ts
│ ├── ledgerLive.ts
│ ├── metamask.ts
│ ├── taho.ts
│ └── walletConnect.ts
│ ├── hooks
│ ├── __tests__
│ │ ├── useContract.test.ts
│ │ ├── useSendTransaction.test.tsx
│ │ ├── useSubscribeToContractEvent.test.ts
│ │ ├── useSubscribeToERC20TransferEvent.test.ts
│ │ ├── useUpgradeToT.test.ts
│ │ ├── useVendingMachineContract.test.ts
│ │ └── useVendingMachineRatio.test.ts
│ ├── index.ts
│ ├── useApproval.ts
│ ├── useApproveTStaking.ts
│ ├── useCheckDuplicateProviderAddress.ts
│ ├── useClaimMerkleRewardsTransaction.ts
│ ├── useContract.ts
│ ├── useERC20.ts
│ ├── useGetBlock.ts
│ ├── useKeep.ts
│ ├── useKeepBondingContract.ts
│ ├── useKeepTokenStakingContract.ts
│ ├── useMerkleDropContract.ts
│ ├── useMulticall.ts
│ ├── useMulticallContract.ts
│ ├── useNu.ts
│ ├── useNuStakingEscrowContract.ts
│ ├── usePREContract.ts
│ ├── useSendTransaction.ts
│ ├── useStakeTransaction.ts
│ ├── useSubscribeToContractEvent.ts
│ ├── useSubscribeToERC20TransferEvent.ts
│ ├── useT.ts
│ ├── useTBTCTokenContract.ts
│ ├── useTBTCv2TokenContract.ts
│ ├── useTStakingAllowance.ts
│ ├── useTStakingContract.ts
│ ├── useTokenAllowance.ts
│ ├── useTopupTransaction.ts
│ ├── useUnstakeTransaction.ts
│ ├── useUpgradeToT.ts
│ ├── useVendingMachineContract.ts
│ └── useVendingMachineRatio.ts
│ ├── library.ts
│ └── utils
│ ├── __tests__
│ └── address.test.ts
│ ├── address.ts
│ ├── connectors.ts
│ ├── doesErrorInclude.ts
│ ├── events.ts
│ ├── files.ts
│ ├── index.ts
│ └── multicall.ts
├── tsconfig.json
└── yarn.lock
/.env.example:
--------------------------------------------------------------------------------
1 | REACT_APP_DEFAULT_PROVIDER_CHAIN_ID=1337
2 | REACT_APP_ALCHEMY_API_KEY=$ALCHEMY_API_KEY
3 | REACT_APP_MULTICALL_ADDRESS=$MULTICALL_ADDRESS
4 | REACT_APP_DAPP_DEVELOPMENT_TESTNET_CONTRACTS=$DAPP_DEVELOPMENT_TESTNET_CONTRACTS
5 |
6 | REACT_APP_FEATURE_FLAG_TBTC_V2=true
7 | REACT_APP_FEATURE_FLAG_TBTC_V2_REDEMPTION=true
8 | REACT_APP_FEATURE_FLAG_MULTI_APP_STAKING=true
9 | REACT_APP_FEATURE_FLAG_FEEDBACK_MODULE=false
10 | REACT_APP_FEATURE_FLAG_LEDGER_LIVE=true
11 |
12 | REACT_APP_FEATURE_FLAG_GOOGLE_TAG_MANAGER=false
13 | REACT_APP_GOOGLE_TAG_MANAGER_ID=$GOOGLE_TAG_MANAGER_ID
14 |
15 | REACT_APP_FEATURE_FLAG_POSTHOG=false
16 |
17 | REACT_APP_FEATURE_FLAG_SENTRY=false
18 | REACT_APP_SENTRY_DSN=$SENTRY_DSN
19 | REACT_APP_FEATURE_FLAG_TRM=false
20 |
21 | REACT_APP_ELECTRUM_PROTOCOL=$ELECTRUM_PROTOCOL
22 | REACT_APP_ELECTRUM_HOST=$ELECTRUM_HOST
23 | REACT_APP_ELECTRUM_PORT=$ELECTRUM_PORT
24 | REACT_APP_MOCK_BITCOIN_CLIENT=true
25 |
26 | REACT_APP_WALLET_CONNECT_PROJECT_ID=$WALLET_CONNECT_PROJECT_ID
27 |
28 | REACT_APP_TBTC_SUBGRAPH_API_KEY=$TBTC_SUBGRAPH_API_KEY
29 |
30 | REACT_APP_TACO_DOMAIN=dashboard
31 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | REACT_APP_DEFAULT_PROVIDER_CHAIN_ID=$CHAIN_ID
2 | REACT_APP_ALCHEMY_API_KEY=$ALCHEMY_API_KEY
3 | REACT_APP_DAPP_DEVELOPMENT_TESTNET_CONTRACTS=$DAPP_DEVELOPMENT_TESTNET_CONTRACTS
4 |
5 | REACT_APP_FEATURE_FLAG_TBTC_V2=true
6 | REACT_APP_FEATURE_FLAG_TBTC_V2_REDEMPTION=true
7 | REACT_APP_FEATURE_FLAG_MULTI_APP_STAKING=true
8 | REACT_APP_FEATURE_FLAG_FEEDBACK_MODULE=false
9 | REACT_APP_FEATURE_FLAG_LEDGER_LIVE=true
10 |
11 | REACT_APP_FEATURE_FLAG_GOOGLE_TAG_MANAGER=$GOOGLE_TAG_MANAGER_SUPPORT
12 | REACT_APP_GOOGLE_TAG_MANAGER_ID=$GOOGLE_TAG_MANAGER_ID
13 |
14 | REACT_APP_FEATURE_FLAG_POSTHOG=$POSTHOG_SUPPORT
15 | REACT_APP_POSTHOG_API_KEY=$POSTHOG_API_KEY
16 | REACT_APP_POSTHOG_HOSTNAME_HTTP=$POSTHOG_HOSTNAME_HTTP
17 |
18 | REACT_APP_FEATURE_FLAG_SENTRY=$SENTRY_SUPPORT
19 | REACT_APP_SENTRY_DSN=$SENTRY_DSN
20 | REACT_APP_FEATURE_FLAG_TRM=$TRM_SUPPORT
21 |
22 | REACT_APP_ELECTRUM_PROTOCOL=$ELECTRUM_PROTOCOL
23 | REACT_APP_ELECTRUM_HOST=$ELECTRUM_HOST
24 | REACT_APP_ELECTRUM_PORT=$ELECTRUM_PORT
25 | REACT_APP_MOCK_BITCOIN_CLIENT=false
26 |
27 | REACT_APP_WALLET_CONNECT_PROJECT_ID=$WALLET_CONNECT_PROJECT_ID
28 |
29 | REACT_APP_TBTC_SUBGRAPH_API_KEY=$TBTC_SUBGRAPH_API_KEY
30 |
31 | REACT_APP_TACO_DOMAIN=mainnet
--------------------------------------------------------------------------------
/.env.test:
--------------------------------------------------------------------------------
1 | REACT_APP_DEFAULT_PROVIDER_CHAIN_ID=1337
2 | REACT_APP_MULTICALL_ADDRESS=0xcA11bde05977b3631167028862bE2a173976CA11
3 | REACT_APP_TACO_DOMAIN=dashboard
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | storybook-static
2 | cypress/fixtures
3 | cypress/plugins
4 | external/
5 | build
6 | dist
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: "@typescript-eslint/parser",
4 | parserOptions: {
5 | ecmaVersion: 2020,
6 | sourceType: "module",
7 | ecmaFeatures: {
8 | jsx: true,
9 | },
10 | },
11 | env: {
12 | browser: true,
13 | es6: true,
14 | },
15 | extends: "eslint-config-keep",
16 | plugins: ["react"],
17 | rules: {
18 | "react/prop-types": 0,
19 | "react/display-name": 0,
20 | "no-invalid-this": 0,
21 | "spaced-comment": 0,
22 | "react/jsx-uses-react": "off",
23 | "react/react-in-jsx-scope": "off",
24 | "no-unused-vars": 0,
25 | },
26 | settings: {
27 | react: {
28 | version: "detect",
29 | },
30 | },
31 | }
32 |
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # Auto-formatted dashboard code via `yarn format:fix` command.
2 |
3 | 50c6d966435451b12691611784aa0dd6ad0927fa
4 | 1911b2106aada277cb49835f9983e4ba04a1affa
5 | b89fbc32ba93e921df994499f3c29512ab59a71e
6 | 0b3d20bbba7a706603c91aef512a5f18d5c8ff17
7 |
--------------------------------------------------------------------------------
/.github/workflows/cypress.yml:
--------------------------------------------------------------------------------
1 | name: Cypress E2E Tests
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | schedule:
8 | - cron: "0 0 * * *"
9 | workflow_dispatch:
10 |
11 | jobs:
12 | cypress-run:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v3
17 | - name: Cypress run
18 | uses: cypress-io/github-action@v2
19 | with:
20 | build: yarn build
21 | start: yarn start
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Local
2 | .DS_Store
3 | .idea
4 | .eslintcache
5 |
6 | # IDEs
7 | .vscode/
8 | .idea/
9 |
10 | # Generated
11 | build/
12 | dist/
13 | external/
14 |
15 | # Storybook
16 | storybook-static
17 | build-storybook.log
18 | cypress/fixtures
19 | cypress/plugins
20 |
21 | # Yarn
22 | node_modules/
23 | yarn-error.log
24 | .env
25 |
26 | .cosine/
27 |
28 | .claude/
29 | CLAUDE.md
30 | coverage/
31 | .do/app.yaml
32 | .env.testnet
33 | .env.mainnet
34 |
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | yarn run pre-commit
5 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,ts,tsx}": "yarn format:fix"
3 | }
4 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 18
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | storybook-static
2 | cypress/fixtures
3 | cypress/plugins
4 | external
5 | build
6 | dist
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | ...require("@keep-network/prettier-config-keep"),
3 | }
4 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: ["../src/stories/*.stories.tsx"],
3 | addons: [
4 | "@storybook/addon-links",
5 | "@storybook/addon-essentials",
6 | "@storybook/preset-create-react-app",
7 | "@snek-at/storybook-addon-chakra-ui",
8 | ],
9 | }
10 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | import theme from "../src/theme"
2 | import { addDecorator } from "@storybook/react"
3 | import { MemoryRouter } from "react-router"
4 |
5 | addDecorator((story) => (
6 | {story()}
7 | ))
8 |
9 | export const parameters = {
10 | actions: { argTypesRegex: "^on[A-Z].*" },
11 | controls: {
12 | matchers: {
13 | color: /(background|color)$/i,
14 | date: /Date$/,
15 | },
16 | },
17 | chakra: { theme },
18 | }
19 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | .github/workflows/dashboard-mainnet.yml @pdyraga @lukasz-zimnoch @cygnusv
2 |
--------------------------------------------------------------------------------
/Dockerfile.dev:
--------------------------------------------------------------------------------
1 | # Use the specified image
2 | FROM node:18-buster-slim
3 |
4 | # Set the working directory
5 | WORKDIR /app
6 |
7 | # Install dependencies
8 | RUN apt-get update && apt-get install -y python3 make g++ git openssh-client ca-certificates && \
9 | git config --global url."https://".insteadOf git:// && \
10 | rm -rf /var/lib/apt/lists/* && \
11 | apt-get clean
12 |
13 | # Set the environment variables
14 | ENV PYTHON=/usr/bin/python3
15 | ENV NODE_OPTIONS=--max_old_space_size=3072
16 |
17 | # Copy package files and install node modules
18 | COPY package*.json yarn.lock ./
19 | RUN npm install -g node-gyp
20 | RUN yarn install --ignore-scripts
21 | RUN yarn upgrade @keep-network/ecdsa@sepolia \
22 | @keep-network/keep-core@sepolia \
23 | @keep-network/keep-ecdsa@sepolia \
24 | @keep-network/random-beacon@sepolia \
25 | @keep-network/tbtc@sepolia \
26 | @keep-network/tbtc-v2@sepolia \
27 | @threshold-network/solidity-contracts@sepolia
28 | RUN yarn run postinstall
29 |
30 | # Expose port 3000
31 | EXPOSE 3000
32 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseUrl": "http://localhost:3000"
3 | }
4 |
--------------------------------------------------------------------------------
/cypress/integration/App.spec.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | describe("My First Test", () => {
4 | it("Opens the app", () => {
5 | cy.visit("/")
6 | cy.dataCy("app-container")
7 | })
8 | })
9 |
--------------------------------------------------------------------------------
/cypress/support/index.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | ///
3 |
4 | declare namespace Cypress {
5 | /**
6 | * A helper method provided by the cypress documentation:
7 | * https://docs.cypress.io/guides/tooling/typescript-support#Types-for-custom-commands
8 | * Custom command to select DOM element by data-cy attribute.
9 | * @example cy.dataCy('greeting')
10 | */
11 | interface Chainable {
12 | dataCy(value: string): Chainable
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/cypress/support/index.ts:
--------------------------------------------------------------------------------
1 | function dataCy(identifier: string) {
2 | return cy.get(`[data-cy=${identifier}]`)
3 | }
4 |
5 | Cypress.Commands.add("dataCy", dataCy)
6 |
--------------------------------------------------------------------------------
/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["es5", "dom"],
5 | "types": ["cypress"],
6 | "isolatedModules": false
7 | },
8 | "include": ["**/*.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.8"
2 |
3 | services:
4 | threshold-dashboard:
5 | container_name: threshold-dashboard
6 | working_dir: /app
7 | environment:
8 | - PYTHON=/usr/bin/python3
9 | - NODE_OPTIONS=--max_old_space_size=3072
10 | ports:
11 | - "3000:3000"
12 | volumes:
13 | - .:/app # Bind mount the current directory to /app in the container
14 | - /app/node_modules # This will prevent node_modules from being overwritten by the local volume
15 | command: bash -c "yarn format:fix && yarn start"
16 | build:
17 | context: .
18 | dockerfile: Dockerfile.dev
19 |
--------------------------------------------------------------------------------
/multicall/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 | artifacts/
4 | build/
5 | cache/
6 | deployments/
7 | export/
8 | export.json
9 |
10 | typechain/
11 |
12 | yarn-error.log
13 |
14 | .vscode/
15 |
16 | .hardhat/*
17 | !.hardhat/networks_TEMPLATE.ts
18 |
--------------------------------------------------------------------------------
/multicall/README.md:
--------------------------------------------------------------------------------
1 | # Deploying `Multicall` via hardhat
2 |
3 | Deploying the
4 | [`Multicall`](https://github.com/makerdao/multicall/blob/master/src/Multicall.sol)
5 | contract to local network via `hardhat` to test integration with
6 | [`Multicall`](https://github.com/makerdao/multicall/blob/master/src/Multicall.sol)
7 | contract in T dapp locally. There is no need to deploy this contract to
8 | `Ropsten` or `Mainnet` network- you can find contract addresses at
9 | https://github.com/makerdao/multicall#multicall-contract-addresses.
10 |
11 | # Prerequisites
12 |
13 | - Make sure your local chain is running (eg. Ganache).
14 | - Verfiy `development` network config in `hardhat.config.ts` file- set the correct `chainId` and `url`.
15 |
16 | # Usage
17 |
18 | ## Setup
19 |
20 | `yarn`
21 |
22 | ## Deploy `Multicall` contract
23 |
24 | `yarn deploy:development`
25 |
--------------------------------------------------------------------------------
/multicall/deploy/01_deploy_multicall.ts:
--------------------------------------------------------------------------------
1 | import { HardhatRuntimeEnvironment } from "hardhat/types"
2 | import { DeployFunction } from "hardhat-deploy/types"
3 |
4 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
5 | const { getNamedAccounts, deployments } = hre
6 | const { deployer } = await getNamedAccounts()
7 |
8 | const Multicall = await deployments.deploy("Multicall", {
9 | from: deployer,
10 | })
11 |
12 | deployments.log(Multicall.address)
13 | }
14 |
15 | export default func
16 |
17 | func.tags = ["Multicall"]
18 |
--------------------------------------------------------------------------------
/multicall/hardhat.config.ts:
--------------------------------------------------------------------------------
1 | import { HardhatUserConfig } from "hardhat/config"
2 |
3 | import "@keep-network/hardhat-helpers"
4 | import "hardhat-deploy"
5 |
6 | const config: HardhatUserConfig = {
7 | solidity: {
8 | compilers: [
9 | {
10 | version: "0.8.9",
11 | settings: {
12 | optimizer: {
13 | enabled: true,
14 | runs: 100,
15 | },
16 | },
17 | },
18 | ],
19 | },
20 | paths: {
21 | artifacts: "./build",
22 | },
23 | networks: {
24 | development: {
25 | url: "http://localhost:8545",
26 | chainId: 1337,
27 | tags: ["local"],
28 | },
29 | },
30 | // // Define local networks configuration file path to load networks from the file.
31 | // localNetworksConfig: "./.hardhat/networks.ts",
32 | namedAccounts: {
33 | deployer: {
34 | default: 0, // take the first account as deployer
35 | },
36 | },
37 | }
38 |
39 | export default config
40 |
--------------------------------------------------------------------------------
/multicall/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multicall",
3 | "description": "Multicall contract deployment via hardhat",
4 | "version": "1.0.0",
5 | "license": "MIT",
6 | "scripts": {
7 | "build": "hardhat compile",
8 | "deploy": "hardhat deploy --export export.json",
9 | "deploy:development": "yarn deploy --network development --reset",
10 | "format": "npm run lint && prettier --check .",
11 | "format:fix": "npm run lint:fix && prettier --write .",
12 | "lint:fix": "eslint . --fix",
13 | "lint": "eslint . "
14 | },
15 | "devDependencies": {
16 | "@keep-network/hardhat-helpers": "^0.2.0-pre.4",
17 | "@keep-network/prettier-config-keep": "github:keep-network/prettier-config-keep#d6ec02e",
18 | "@nomiclabs/hardhat-ethers": "^2.0.2",
19 | "eslint": "^7.27.0",
20 | "eslint-config-keep": "github:keep-network/eslint-config-keep#0c27ade",
21 | "ethers": "^5.4.1",
22 | "hardhat-deploy": "^0.9.4",
23 | "hardhat": "^2.6.8",
24 | "prettier": "^2.3.2",
25 | "prettier-plugin-sh": "^0.7.1",
26 | "ts-node": "^10.4.0",
27 | "typescript": "^4.4.4"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/multicall/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": ["./hardhat.config.ts"],
3 | "include": ["./deploy"]
4 | }
5 |
--------------------------------------------------------------------------------
/public/Metabanner_grid.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/public/Metabanner_grid.jpg
--------------------------------------------------------------------------------
/public/favicon-T.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/public/favicon-T.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/scripts/rebuild_components_package.sh:
--------------------------------------------------------------------------------
1 | LOG_START='\n\e[1;36m' # new line + bold + color
2 | LOG_END='\n\e[0m' # new line + reset color
3 |
4 | set -e -x
5 |
6 | TIMESTAMP=`date "+%s"`
7 | printf "${LOG_START}Removing components from node_modules folder...${LOG_END}"
8 | rm -rf node_modules/components
9 | printf "${LOG_START}Building components...${LOG_END}"
10 | yarn --cwd ../components/ build
11 | printf "${LOG_START}Packing components...${LOG_END}"
12 | yarn --cwd ../components/ pack --filename components-$TIMESTAMP.tgz
13 | printf "${LOG_START}Installing the lib${LOG_END}"
14 | yarn add file:components-$TIMESTAMP.tgz
15 | printf "${LOG_START}Removing packed file...${LOG_END}"
16 | rm components-$TIMESTAMP.tgz
17 |
18 | printf "${LOG_START}Done!.${LOG_END}"
19 |
--------------------------------------------------------------------------------
/src/__mocks__/@starknet-react/chains.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mainnet: {
3 | id: BigInt("0x534e5f4d41494e"),
4 | name: "Starknet Mainnet",
5 | },
6 | sepolia: {
7 | id: BigInt("0x534e5f5345504f4c4941"),
8 | name: "Starknet Sepolia",
9 | },
10 | goerli: {
11 | id: BigInt("0x534e5f474f45524c49"),
12 | name: "Starknet Goerli (Deprecated)",
13 | },
14 | }
15 |
--------------------------------------------------------------------------------
/src/__mocks__/@starknet-react/core.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | StarknetConfig: jest.fn(),
3 | useAccount: jest.fn(),
4 | useProvider: jest.fn(),
5 | useConnect: jest.fn(),
6 | useDisconnect: jest.fn(),
7 | useNetwork: jest.fn(),
8 | useStarknet: jest.fn(),
9 | }
10 |
--------------------------------------------------------------------------------
/src/__mocks__/axios.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | default: {
3 | get: jest.fn(() => Promise.resolve({ data: {} })),
4 | post: jest.fn(() => Promise.resolve({ data: {} })),
5 | put: jest.fn(() => Promise.resolve({ data: {} })),
6 | delete: jest.fn(() => Promise.resolve({ data: {} })),
7 | create: jest.fn(() => ({
8 | get: jest.fn(() => Promise.resolve({ data: {} })),
9 | post: jest.fn(() => Promise.resolve({ data: {} })),
10 | put: jest.fn(() => Promise.resolve({ data: {} })),
11 | delete: jest.fn(() => Promise.resolve({ data: {} })),
12 | })),
13 | },
14 | get: jest.fn(() => Promise.resolve({ data: {} })),
15 | post: jest.fn(() => Promise.resolve({ data: {} })),
16 | put: jest.fn(() => Promise.resolve({ data: {} })),
17 | delete: jest.fn(() => Promise.resolve({ data: {} })),
18 | create: jest.fn(() => ({
19 | get: jest.fn(() => Promise.resolve({ data: {} })),
20 | post: jest.fn(() => Promise.resolve({ data: {} })),
21 | put: jest.fn(() => Promise.resolve({ data: {} })),
22 | delete: jest.fn(() => Promise.resolve({ data: {} })),
23 | })),
24 | }
25 |
--------------------------------------------------------------------------------
/src/__mocks__/multiformats.js:
--------------------------------------------------------------------------------
1 | // Mock for multiformats to fix dependency issues
2 | module.exports = {
3 | bases: {
4 | base16: {
5 | encode: jest.fn((data) => data.toString("hex")),
6 | decode: jest.fn((str) => Buffer.from(str, "hex")),
7 | },
8 | base32: {
9 | encode: jest.fn((data) => data.toString("base64")),
10 | decode: jest.fn((str) => Buffer.from(str, "base64")),
11 | },
12 | base64: {
13 | encode: jest.fn((data) => data.toString("base64")),
14 | decode: jest.fn((str) => Buffer.from(str, "base64")),
15 | },
16 | },
17 | }
18 |
--------------------------------------------------------------------------------
/src/__mocks__/starknet.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | Account: jest.fn(),
3 | Provider: jest.fn(),
4 | constants: {
5 | StarknetChainId: {
6 | MAINNET: "0x534e5f4d41494e",
7 | TESTNET: "0x534e5f5345504f4c4941",
8 | },
9 | },
10 | RpcProvider: jest.fn(),
11 | }
12 |
--------------------------------------------------------------------------------
/src/__mocks__/starknetkit.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | connect: jest.fn(),
3 | disconnect: jest.fn(),
4 | getAvailableWallets: jest.fn().mockReturnValue([]),
5 | }
6 |
--------------------------------------------------------------------------------
/src/__mocks__/threshold-ts/index.ts:
--------------------------------------------------------------------------------
1 | export class TBTC {
2 | getEstimatedDepositFees = jest.fn()
3 | revealDeposit = jest.fn()
4 | bridgeContract = true
5 | }
6 |
7 | export class Threshold {
8 | tbtc: TBTC
9 |
10 | constructor() {
11 | this.tbtc = new TBTC()
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/__mocks__/uint8arrays.js:
--------------------------------------------------------------------------------
1 | // Mock for uint8arrays to fix WalletConnect import issues in tests
2 | module.exports = {
3 | fromString: jest.fn((str) => Buffer.from(str)),
4 | toString: jest.fn((arr) => Buffer.from(arr).toString()),
5 | concat: jest.fn((arrays) => Buffer.concat(arrays)),
6 | equals: jest.fn((a, b) => Buffer.from(a).equals(Buffer.from(b))),
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/BundledRewardsAlert/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | Alert,
4 | AlertIcon,
5 | AlertDescription,
6 | AlertProps,
7 | BodyXs,
8 | } from "@threshold-network/components"
9 |
10 | const defaultText =
11 | "tBTC + Random Beacon earn bundled rewards. Authorize both apps to earn rewards."
12 |
13 | const BundledRewardsAlert: FC<{ text?: string } & AlertProps> = ({
14 | text = defaultText,
15 | ...restProps
16 | }) => {
17 | return (
18 |
19 |
20 | {text}
21 |
22 | )
23 | }
24 |
25 | export default BundledRewardsAlert
26 |
--------------------------------------------------------------------------------
/src/components/ButtonLink/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Button, ButtonProps, forwardRef } from "@threshold-network/components"
3 | import Link, { LinkProps } from "../Link"
4 |
5 | const style = {
6 | textDecoration: "none",
7 | }
8 |
9 | const ButtonLink: FC = forwardRef(
10 | ({ ...props }, ref) => {
11 | return (
12 |
19 | )
20 | }
21 | )
22 |
23 | export default ButtonLink
24 |
--------------------------------------------------------------------------------
/src/components/DotsLoadingIndicator/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | Box,
4 | HStack,
5 | StackProps,
6 | ThemingProps,
7 | useStyleConfig,
8 | } from "@threshold-network/components"
9 |
10 | type DotsLoadingIndicatorProps = StackProps & Omit
11 |
12 | export const DotsLoadingIndicator: FC = ({
13 | colorScheme = "brand",
14 | size = "sm",
15 | ...restProps
16 | }) => {
17 | const styles = useStyleConfig("DotsLoadingIndicator", {
18 | colorScheme,
19 | size,
20 | })
21 |
22 | return (
23 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/Forms/Form.tsx:
--------------------------------------------------------------------------------
1 | import { chakra } from "@chakra-ui/react"
2 | import { Form as FormikForm } from "formik"
3 |
4 | export const Form = chakra(FormikForm)
5 |
--------------------------------------------------------------------------------
/src/components/Forms/FormikTokenBalanceInput.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { useField } from "formik"
3 | import TokenBalanceInput, { TokenBalanceInputProps } from "../TokenBalanceInput"
4 |
5 | export type FormikTokenBalanceInput = {
6 | name: string
7 | } & Omit
8 |
9 | export const FormikTokenBalanceInput: FC = ({
10 | name,
11 | ...restProps
12 | }) => {
13 | const [field, meta, helpers] = useField(name)
14 |
15 | return (
16 |
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/Forms/HelperErrorText.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | Box,
4 | FormErrorMessage,
5 | FormHelperText,
6 | } from "@threshold-network/components"
7 |
8 | const HelperErrorText: FC<{
9 | errorMsgText?: string | JSX.Element
10 | hasError?: boolean
11 | helperText?: string | JSX.Element
12 | }> = ({ errorMsgText, helperText, hasError }) => {
13 | return (
14 |
15 | {hasError ? (
16 |
17 | {errorMsgText || "Please enter a valid value"}
18 |
19 | ) : helperText ? (
20 | {helperText}
21 | ) : null}
22 |
23 | )
24 | }
25 |
26 | export default HelperErrorText
27 |
--------------------------------------------------------------------------------
/src/components/Forms/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./TokenAmountForm"
2 | export * from "./Form"
3 | export * from "./FormikInput"
4 | export * from "./FormikTokenBalanceInput"
5 |
--------------------------------------------------------------------------------
/src/components/Identicon.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import createIdenticon from "ethereum-blockies-base64"
3 | import { Image } from "@chakra-ui/react"
4 |
5 | const Identicon: FC<{ address: string }> = ({ address }) => {
6 | return (
7 |
14 | )
15 | }
16 |
17 | export default Identicon
18 |
--------------------------------------------------------------------------------
/src/components/InfoBox/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { StackProps, Stack, useStyleConfig } from "@chakra-ui/react"
3 | import { H3 } from "@threshold-network/components"
4 |
5 | const InfoBox: FC<{ text?: string; variant?: any } & StackProps> = ({
6 | text,
7 | children,
8 | variant = "base",
9 | ...props
10 | }) => {
11 | const styles = useStyleConfig("InfoBox", { variant })
12 |
13 | return (
14 |
15 | {text && {text}
}
16 | {children}
17 |
18 | )
19 | }
20 |
21 | export default InfoBox
22 |
--------------------------------------------------------------------------------
/src/components/Link/SharedLinks.tsx:
--------------------------------------------------------------------------------
1 | import { FC, ComponentProps } from "react"
2 | import { useColorModeValue } from "@chakra-ui/react"
3 | import { BodySm } from "@threshold-network/components"
4 | import ViewInBlockExplorer from "../ViewInBlockExplorer"
5 | import { useTStakingContract } from "../../web3/hooks"
6 | import { ExplorerDataType } from "../../networks/enums/networks"
7 |
8 | type StakingContractLearnMoreProps = ComponentProps
9 |
10 | export const StakingContractLearnMore: FC = (
11 | props
12 | ) => {
13 | const tStakingContract = useTStakingContract()
14 | const color = useColorModeValue("gray.500", "gray.300")
15 |
16 | if (tStakingContract?.address) {
17 | return (
18 |
19 | Read the{" "}
20 |
25 |
26 | )
27 | }
28 |
29 | return null
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/MintDurationTiers/index.ts:
--------------------------------------------------------------------------------
1 | export { default as MintDurationTiers } from "./MintDurationTiers"
2 |
--------------------------------------------------------------------------------
/src/components/MintDurationWidget/index.ts:
--------------------------------------------------------------------------------
1 | export { default as MintDurationWidget } from "./MintDurationWidget"
2 |
--------------------------------------------------------------------------------
/src/components/Modal/DeauthorizeApplicationModal/index.tsx:
--------------------------------------------------------------------------------
1 | import InitiateDeauthorization from "./InititateDeauthorization"
2 | import withBaseModal from "../withBaseModal"
3 |
4 | export default withBaseModal(InitiateDeauthorization)
5 |
--------------------------------------------------------------------------------
/src/components/Modal/ModalCloseButton.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | ModalCloseButton as _ModalCloseButton,
4 | CloseButtonProps,
5 | } from "@threshold-network/components"
6 |
7 | const ModalCloseButton: FC = (props) => {
8 | return <_ModalCloseButton className="ph-no-capture" {...props} />
9 | }
10 |
11 | export default ModalCloseButton
12 |
--------------------------------------------------------------------------------
/src/components/Modal/ModalRoot.tsx:
--------------------------------------------------------------------------------
1 | import { useModal } from "../../hooks/useModal"
2 | import { MODAL_TYPES } from "../../types"
3 |
4 | const ModalRoot = () => {
5 | const { modalType, modalProps, closeModal } = useModal()
6 |
7 | if (!modalType) {
8 | return <>>
9 | }
10 | const SpecificModal = MODAL_TYPES[modalType]
11 | return
12 | }
13 |
14 | export default ModalRoot
15 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/ConnectSui.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { WalletConnectionModalBase } from "./components"
3 | import SuiWalletList from "./SuiWalletList"
4 | import { SuiIcon } from "../../../static/icons/Sui"
5 |
6 | const ConnectSui: FC<{
7 | goBack: () => void
8 | closeModal: () => void
9 | }> = ({ goBack, closeModal }) => (
10 |
17 |
18 |
19 | )
20 |
21 | export default ConnectSui
22 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/AccountSuccessAlert.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { useWeb3React } from "@web3-react/core"
3 | import {
4 | Alert,
5 | AlertDescription,
6 | AlertIcon,
7 | AlertTitle,
8 | Stack,
9 | } from "@chakra-ui/react"
10 | import shortenAddress from "../../../../utils/shortenAddress"
11 |
12 | const AccountSuccessAlert: FC<{ message: string }> = ({ message }) => {
13 | const { account } = useWeb3React()
14 |
15 | return (
16 |
17 |
18 |
19 | {message}
20 |
21 | Address: {shortenAddress(account || "")}
22 |
23 |
24 |
25 | )
26 | }
27 |
28 | export default AccountSuccessAlert
29 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/CoinbaseStatusAlert.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { useWeb3React } from "@web3-react/core"
3 | import {
4 | AccountSuccessAlert,
5 | WalletInitializeAlert,
6 | WalletRejectedAlert,
7 | } from "."
8 | import { Alert, AlertDescription, AlertIcon } from "@chakra-ui/react"
9 |
10 | const CoinbaseStatusAlert: FC<{
11 | connectionRejected?: boolean
12 | unsupportedChainId?: boolean
13 | }> = ({ connectionRejected, unsupportedChainId }) => {
14 | const { active } = useWeb3React()
15 |
16 | if (connectionRejected) {
17 | return
18 | }
19 |
20 | if (unsupportedChainId) {
21 | return (
22 |
23 |
24 | Unsupported Network.
25 |
26 | )
27 | }
28 |
29 | if (active) {
30 | return
31 | }
32 | return
33 | }
34 |
35 | export default CoinbaseStatusAlert
36 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/IncorrectNetwork.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | Alert,
4 | AlertDescription,
5 | AlertIcon,
6 | AlertTitle,
7 | Stack,
8 | } from "@chakra-ui/react"
9 |
10 | const IncorrectNetworkAlert: FC = () => {
11 | return (
12 |
13 |
14 |
15 | Incorrect Network
16 |
17 | Please connect to a supported network.
18 |
19 |
20 |
21 | )
22 | }
23 |
24 | export default IncorrectNetworkAlert
25 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/MetamaskNotInstalledAlert.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Alert, AlertDescription, AlertIcon } from "@chakra-ui/react"
3 | import { ExternalHref } from "../../../../enums"
4 | import Link from "../../../Link"
5 |
6 | const MetamaskNotInstalledAlert: FC = () => {
7 | return (
8 |
9 |
10 |
11 | MetaMask is not installed. Please install the MetaMask extension on{" "}
12 |
13 | their website
14 |
15 |
16 |
17 | )
18 | }
19 |
20 | export default MetamaskNotInstalledAlert
21 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/MetamaskStatusAlert.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { useWeb3React } from "@web3-react/core"
3 | import {
4 | AccountSuccessAlert,
5 | MetamaskNotInstalledAlert,
6 | WalletInitializeAlert,
7 | WalletRejectedAlert,
8 | } from "."
9 |
10 | const MetamaskStatusAlert: FC<{
11 | metamaskNotInstalled?: boolean
12 | connectionRejected?: boolean
13 | isMetaMask: boolean
14 | }> = ({ metamaskNotInstalled, connectionRejected, isMetaMask }) => {
15 | const { active } = useWeb3React()
16 | if (metamaskNotInstalled) {
17 | return
18 | }
19 | if (connectionRejected) {
20 | return
21 | }
22 | if (!isMetaMask) {
23 | return (
24 | <>
25 | window.ethereum is not MetaMask. Make sure you have MetaMask extension
26 | installed and MetaMask is your default wallet.
27 | >
28 | )
29 | }
30 | if (active) {
31 | return
32 | }
33 | return
34 | }
35 |
36 | export default MetamaskStatusAlert
37 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/WalletConnectStatusAlert.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { AccountSuccessAlert, WalletInitializeAlert } from "./index"
3 | import WalletRejectedAlert from "./WalletRejectedAlert"
4 | import { isSupportedNetwork } from "../../../../networks/utils"
5 | import { useWeb3React } from "@web3-react/core"
6 | import IncorrectNetwork from "./IncorrectNetwork"
7 |
8 | const WalletConnectStatusAlert: FC<{
9 | connectionRejected?: boolean
10 | active?: boolean
11 | }> = ({ connectionRejected, active }) => {
12 | const { chainId } = useWeb3React()
13 | const networkOK = isSupportedNetwork(chainId)
14 |
15 | if (connectionRejected) {
16 | return
17 | }
18 |
19 | if (active && !networkOK) {
20 | return
21 | }
22 |
23 | if (active) {
24 | return (
25 |
26 | )
27 | }
28 |
29 | return
30 | }
31 |
32 | export default WalletConnectStatusAlert
33 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/WalletInitializeAlert.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Alert, AlertDescription, Spinner } from "@chakra-ui/react"
3 |
4 | const WalletInitializeAlert: FC = () => {
5 | return (
6 |
7 |
14 | Initializing wallet connection...
15 |
16 | )
17 | }
18 |
19 | export default WalletInitializeAlert
20 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/WalletRejectedAlert.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Alert, AlertDescription, AlertIcon } from "@chakra-ui/react"
3 |
4 | const WalletRejectedAlert: FC = () => {
5 | return (
6 |
7 |
8 | User rejected the connection request.
9 |
10 | )
11 | }
12 |
13 | export default WalletRejectedAlert
14 |
--------------------------------------------------------------------------------
/src/components/Modal/SelectWalletModal/components/index.ts:
--------------------------------------------------------------------------------
1 | import AccountSuccessAlert from "./AccountSuccessAlert"
2 | import WalletInitializeAlert from "./WalletInitializeAlert"
3 | import WalletConnectionModalBase from "./WalletConnectionModalBase"
4 | import WalletRejectedAlert from "./WalletRejectedAlert"
5 | import MetamaskNotInstalledAlert from "./MetamaskNotInstalledAlert"
6 | import MetamaskStatusAlert from "./MetamaskStatusAlert"
7 | import WalletConnectStatusAlert from "./WalletConnectStatusAlert"
8 |
9 | export {
10 | AccountSuccessAlert,
11 | WalletInitializeAlert,
12 | WalletRejectedAlert,
13 | WalletConnectionModalBase,
14 | MetamaskNotInstalledAlert,
15 | MetamaskStatusAlert,
16 | WalletConnectStatusAlert,
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/Modal/StakingApplications/index.ts:
--------------------------------------------------------------------------------
1 | export { AuthorizeStakingApps } from "./AuthorizeStakingApps"
2 | export { StakingApplicationsAuthorized } from "./StakingApplicationsAuthorized"
3 | export { IncreaseAuthorization } from "./IncreaseAuthorization"
4 | export { IncreaseAuthorizationSuccess } from "./IncreaseAuthorizationSuccess"
5 | export { ConfirmDeauthorization } from "./ConfirmDeauthorization"
6 | export { DeauthorizationCompleted } from "./DeauthorizationCompleted"
7 | export { DeauthorizationInitiated } from "./DeauthorizationInitiated"
8 |
--------------------------------------------------------------------------------
/src/components/Modal/TopupTModal/index.tsx:
--------------------------------------------------------------------------------
1 | import TopupTModal from "./TopUpTModal"
2 | import LegacyTopUpModal from "./LegacyTopUpModal"
3 |
4 | export { LegacyTopUpModal, TopupTModal }
5 |
--------------------------------------------------------------------------------
/src/components/Modal/TopupTSuccessModal/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import withBaseModal from "../withBaseModal"
3 | import { BaseModalProps } from "../../../types"
4 | import TransactionSuccessModal from "../TransactionSuccessModal"
5 | import StakingStats from "../../StakingStats"
6 | import { StakeData } from "../../../types/staking"
7 |
8 | interface TopupTSuccessProps extends BaseModalProps {
9 | transactionHash: string
10 | stake: StakeData
11 | stakeAmount: string | number
12 | }
13 |
14 | const TopupTSuccessModal: FC = ({
15 | transactionHash,
16 | stake: { beneficiary, stakingProvider, authorizer },
17 | stakeAmount,
18 | }) => {
19 | return (
20 |
27 | }
28 | />
29 | )
30 | }
31 |
32 | export default withBaseModal(TopupTSuccessModal)
33 |
--------------------------------------------------------------------------------
/src/components/Modal/TransactionModal/TransactionIsWaitingForConfirmation.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { ModalBody, ModalHeader } from "@chakra-ui/react"
3 | import { BodyLg } from "@threshold-network/components"
4 | import withBaseModal from "../withBaseModal"
5 | import { BaseModalProps } from "../../../types"
6 | import InfoBox from "../../InfoBox"
7 | import { ThresholdSpinner } from "../../ThresholdSpinner/ThresholdSpinner"
8 | import ModalCloseButton from "../ModalCloseButton"
9 |
10 | interface Props extends BaseModalProps {
11 | pendingText?: string
12 | }
13 |
14 | const TransactionIsWaitingForConfirmation: FC = ({
15 | pendingText = "Please confirm the transaction in your wallet",
16 | }) => {
17 | return (
18 | <>
19 | Confirm (waiting)
20 |
21 |
22 |
23 |
24 |
25 | {pendingText}
26 |
27 |
28 |
29 | >
30 | )
31 | }
32 |
33 | export default withBaseModal(TransactionIsWaitingForConfirmation)
34 |
--------------------------------------------------------------------------------
/src/components/Modal/TransactionModal/index.ts:
--------------------------------------------------------------------------------
1 | import TransactionIsPending from "./TransactionIsPending"
2 | import TransactionIsWaitingForConfirmation from "./TransactionIsWaitingForConfirmation"
3 | import TransactionFailed from "./TransactionFailed"
4 |
5 | export {
6 | TransactionIsPending,
7 | TransactionIsWaitingForConfirmation,
8 | TransactionFailed,
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/Modal/UnstakeTModal/DeauthorizeInfo.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { BodyLg } from "@threshold-network/components"
3 | import ButtonLink from "../../ButtonLink"
4 |
5 | export const DeauthorizeInfo: FC<{ stakingProvider: string }> = ({
6 | stakingProvider,
7 | }) => {
8 | return (
9 | <>
10 |
11 | Make sure you deauthorized all the applications using your stake funds.
12 |
13 |
14 |
21 | Deauthorize Applications
22 |
23 | >
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/Modal/UnstakeTModal/index.tsx:
--------------------------------------------------------------------------------
1 | import UnstakeTStep1 from "./Step1"
2 | import UnstakeTStep2 from "./Step2"
3 |
4 | export { UnstakeTStep1, UnstakeTStep2 }
5 |
--------------------------------------------------------------------------------
/src/components/Modal/UpgradeToTModal/index.tsx:
--------------------------------------------------------------------------------
1 | import TransactionIdle from "./TransactionIdle"
2 | import TransactionSuccess from "./UpgradeSuccess"
3 |
4 | export { TransactionIdle, TransactionSuccess }
5 |
--------------------------------------------------------------------------------
/src/components/Modal/index.ts:
--------------------------------------------------------------------------------
1 | import ModalRoot from "./ModalRoot"
2 |
3 | export default ModalRoot
4 |
--------------------------------------------------------------------------------
/src/components/Modal/tBTC/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./NewTBTCApp"
2 | export * from "./GenerateNewDepositAddress"
3 | export * from "./InitiateUnminting"
4 |
--------------------------------------------------------------------------------
/src/components/Modal/withBaseModal.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentType } from "react"
2 | import { Modal, ModalContent, ModalOverlay } from "@chakra-ui/react"
3 | import { BaseModalProps } from "../../types"
4 |
5 | function withBaseModal(
6 | WrappedModalContent: ComponentType
7 | ) {
8 | return (props: T) => {
9 | return (
10 |
16 |
17 |
18 |
19 |
20 |
21 | )
22 | }
23 | }
24 |
25 | export default withBaseModal
26 |
--------------------------------------------------------------------------------
/src/components/Navbar/DarkModeSwitcher.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | Icon,
4 | IconButton,
5 | IconButtonProps,
6 | useColorMode,
7 | useColorModeValue,
8 | } from "@threshold-network/components"
9 | import { IoMoonSharp, IoSunnySharp } from "react-icons/all"
10 |
11 | const DarkModeSwitcher: FC> = () => {
12 | const { toggleColorMode } = useColorMode()
13 | const icon = useColorModeValue(IoMoonSharp, IoSunnySharp)
14 |
15 | return (
16 | }
21 | />
22 | )
23 | }
24 |
25 | export default DarkModeSwitcher
26 |
--------------------------------------------------------------------------------
/src/components/Navbar/HamburgerButton.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Icon, IconButton, IconButtonProps } from "@chakra-ui/react"
3 | import { HamburgerIcon } from "@chakra-ui/icons"
4 | import { useSidebar } from "../../hooks/useSidebar"
5 |
6 | const HamburgerButton: FC> = (props) => {
7 | const { openSidebar } = useSidebar()
8 | return (
9 | }
14 | {...props}
15 | />
16 | )
17 | }
18 |
19 | export default HamburgerButton
20 |
--------------------------------------------------------------------------------
/src/components/NotificationPill/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Box, useStyleConfig } from "@chakra-ui/react"
3 | import {
4 | ThemingProps,
5 | HTMLChakraProps,
6 | omitThemingProps,
7 | } from "@chakra-ui/system"
8 |
9 | export interface NotificationPillProps
10 | extends HTMLChakraProps<"div">,
11 | ThemingProps<"NotificationPill"> {}
12 |
13 | // Notification pill icon indicates a change in state.
14 | const NotificationPill: FC = (props) => {
15 | const { variant, size } = props
16 | const styles = useStyleConfig("NotificationPill", {
17 | variant,
18 | size,
19 | } as ThemingProps)
20 |
21 | const restProps = omitThemingProps(props as ThemingProps)
22 |
23 | return
24 | }
25 |
26 | export default NotificationPill
27 |
--------------------------------------------------------------------------------
/src/components/OutlineListItem.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | ListItem,
4 | ListItemProps,
5 | useColorModeValue,
6 | } from "@threshold-network/components"
7 |
8 | export const OutlineListItem: FC = ({ ...props }) => {
9 | const borderColor = useColorModeValue("gray.100", "gray.700")
10 |
11 | return (
12 |
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/QRCode/index.tsx:
--------------------------------------------------------------------------------
1 | import { HTMLChakraProps } from "@chakra-ui/react"
2 | import React, { FC } from "react"
3 | import ReactQRCode, { QRCodeProps } from "react-qr-code"
4 |
5 | export interface QrCodeWrapperProps extends Omit {}
6 |
7 | export const QRCode: FC = (props) => {
8 | return
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/Sidebar/ExpanderIcon.tsx:
--------------------------------------------------------------------------------
1 | import { Icon, useColorModeValue } from "@chakra-ui/react"
2 | import { BiChevronLeft, BiChevronRight } from "react-icons/all"
3 | import { useSidebar } from "../../hooks/useSidebar"
4 |
5 | const ExpanderIcon = () => {
6 | const { isOpen, openSidebar, closeSidebar } = useSidebar()
7 | return (
8 |
24 | )
25 | }
26 |
27 | export default ExpanderIcon
28 |
--------------------------------------------------------------------------------
/src/components/Sidebar/MobileSidebar.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | Box,
4 | Drawer,
5 | DrawerContent,
6 | DrawerOverlay,
7 | Stack,
8 | } from "@chakra-ui/react"
9 | import { useSidebar } from "../../hooks/useSidebar"
10 | import SidebarFooter from "./SidebarFooter"
11 | import BrandIcon from "./BrandIcon"
12 | import NavItem, { NavItemDetail } from "./NavItem"
13 | import useChakraBreakpoint from "../../hooks/useChakraBreakpoint"
14 |
15 | const MobileSidebar: FC<{ navItems: NavItemDetail[] }> = ({ navItems }) => {
16 | const { isOpen, closeSidebar } = useSidebar()
17 | const breakpoint = useChakraBreakpoint("md")
18 |
19 | return (
20 |
25 |
26 |
27 |
28 |
29 |
30 | {navItems.map((props) => (
31 |
32 | ))}
33 |
34 |
35 |
36 |
37 |
38 | )
39 | }
40 |
41 | export default MobileSidebar
42 |
--------------------------------------------------------------------------------
/src/components/Spinner.tsx:
--------------------------------------------------------------------------------
1 | import { Flex, Icon, Spinner as ChakraSpinner } from "@chakra-ui/react"
2 | import Threshold from "../static/icons/Ttoken"
3 |
4 | // Maybe we should build this component in Chakra way and make it more
5 | // reusable.
6 | const Spinner = () => {
7 | return (
8 |
9 |
17 |
18 |
19 | )
20 | }
21 |
22 | export default Spinner
23 |
--------------------------------------------------------------------------------
/src/components/ThresholdSpinner/ThresholdSpinner.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from "react"
2 | import { IconSpinner } from "@threshold-network/components"
3 | import Threshold from "../../static/icons/Ttoken"
4 |
5 | export const ThresholdSpinner: FC = () => {
6 | // @ts-ignore
7 | return
8 | }
9 |
--------------------------------------------------------------------------------
/src/components/Timeline/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./Timeline"
2 |
--------------------------------------------------------------------------------
/src/components/Toast/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Toast } from "./Toast"
2 |
--------------------------------------------------------------------------------
/src/components/TransactionInfoTable/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { HStack, Stack } from "@chakra-ui/react"
3 | import { BodySm } from "@threshold-network/components"
4 |
5 | export interface TransactionInfo {
6 | text: string
7 | value: JSX.Element
8 | }
9 |
10 | const TransactionInfoTable: FC<{ transactionInfo: TransactionInfo[] }> = ({
11 | transactionInfo,
12 | }) => {
13 | return (
14 |
15 | {transactionInfo.map((info) => (
16 |
17 | {info.text}
18 | {info.value}
19 |
20 | ))}
21 |
22 | )
23 | }
24 |
25 | export default TransactionInfoTable
26 |
--------------------------------------------------------------------------------
/src/components/Tree/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./Tree"
2 |
--------------------------------------------------------------------------------
/src/components/UpgradeIconGroup.tsx:
--------------------------------------------------------------------------------
1 | import { Token } from "../enums"
2 | import { Box, HStack, Icon, Stack } from "@chakra-ui/react"
3 | import KeepCircleBrand from "../static/icons/KeepCircleBrand"
4 | import NuCircleBrand from "../static/icons/NuCircleBrand"
5 | import { BsArrowRightShort } from "react-icons/all"
6 | import T from "../static/icons/Ttoken"
7 | import React, { FC } from "react"
8 |
9 | const UpgradeIconGroup: FC<{ token: Token; boxSize?: number | string }> = ({
10 | token,
11 | boxSize = "32px",
12 | }) => {
13 | return (
14 |
15 | {token === Token.Keep && (
16 |
17 | )}
18 | {token === Token.Nu && (
19 |
20 | )}
21 |
28 |
29 |
30 | )
31 | }
32 |
33 | export default UpgradeIconGroup
34 |
--------------------------------------------------------------------------------
/src/components/tBTC/BridgeProcessIndicator.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { HStack, Image, StackProps } from "@threshold-network/components"
3 | import { DotsLoadingIndicator } from "../DotsLoadingIndicator"
4 | import { BridgeProcess } from "../../types/tbtc"
5 | import tBTCIcon from "../../static/images/tBTC.svg"
6 | import BitcoinIcon from "../../static/images/bitcoin.svg"
7 |
8 | export const BridgeProcessIndicator: FC<
9 | {
10 | bridgeProcess: BridgeProcess
11 | } & StackProps
12 | > = ({ bridgeProcess, ...restProps }) => {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/tBTC/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./BridgeActivity"
2 | export * from "./BridgeProcessIndicator"
3 | export * from "./Links"
4 | export * from "./SendBitcoinsToDepositAddressForm"
5 | export * from "./Stats"
6 | export * from "./TakeNoteList"
7 | export * from "./tBTCText"
8 |
--------------------------------------------------------------------------------
/src/components/tBTC/tBTCText.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Box, BoxProps } from "@threshold-network/components"
3 |
4 | export const TBTCText: FC = (props) => {
5 | return (
6 |
7 |
8 | t
9 |
10 | BTC
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/withOnlyConnectedWallet.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentType } from "react"
2 | import { H5 } from "@threshold-network/components"
3 | import { useIsActive } from "../hooks/useIsActive"
4 | import { useNonEVMConnection } from "../hooks/useNonEVMConnection"
5 |
6 | function withOnlyConnectedWallet(
7 | Component: ComponentType,
8 | renderNotConnected?: () => JSX.Element
9 | ) {
10 | return (props: T & {}) => {
11 | const { account, isActive } = useIsActive()
12 | const isNonEVMActive = useNonEVMConnection()
13 |
14 | if ((isActive && account) || isNonEVMActive) {
15 | return
16 | }
17 | return renderNotConnected ? (
18 | renderNotConnected()
19 | ) : (
20 | Wallet not connected
21 | )
22 | }
23 | }
24 |
25 | export default withOnlyConnectedWallet
26 |
--------------------------------------------------------------------------------
/src/components/withWalletConnection.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentType } from "react"
2 | import { H5 } from "@threshold-network/components"
3 | import { useIsActive } from "../hooks/useIsActive"
4 | import { useNonEVMConnection } from "../hooks/useNonEVMConnection"
5 |
6 | function withWalletConnection(
7 | Component: ComponentType,
8 | renderNotConnected?: () => JSX.Element
9 | ) {
10 | return (props: T & {}) => {
11 | const { account, isActive } = useIsActive()
12 | const { isNonEVMActive } = useNonEVMConnection()
13 |
14 | // Check for either EVM or non-EVM wallet connection
15 | const isWalletConnected = (isActive && account) || isNonEVMActive
16 |
17 | if (!isWalletConnected) {
18 | return renderNotConnected ? (
19 | renderNotConnected()
20 | ) : (
21 | Wallet not connected
22 | )
23 | }
24 | return
25 | }
26 | }
27 |
28 | export default withWalletConnection
29 |
--------------------------------------------------------------------------------
/src/constants/featureFlags.ts:
--------------------------------------------------------------------------------
1 | import { EnvVariable } from "../enums"
2 | import { getEnvVariable } from "../utils/getEnvVariable"
3 |
4 | export const TBTC_V2 =
5 | getEnvVariable(EnvVariable.FEATURE_FLAG_TBTC_V2) === "true"
6 |
7 | export const MULTI_APP_STAKING =
8 | getEnvVariable(EnvVariable.FEATURE_FLAG_MULTI_APP_STAKING) === "true"
9 |
10 | export const POSTHOG =
11 | getEnvVariable(EnvVariable.FEATURE_FLAG_POSTHOG) === "true" &&
12 | !window.location.href.includes("dashboard.test")
13 |
14 | export const TRM = getEnvVariable(EnvVariable.FEATURE_FLAG_TRM) === "true"
15 |
16 | export const FEEDBACK_MODULE =
17 | getEnvVariable(EnvVariable.FEATURE_FLAG_FEEDBACK_MODULE) === "true"
18 |
19 | export const SENTRY = getEnvVariable(EnvVariable.FEATURE_FLAG_SENTRY) === "true"
20 |
21 | export const TBTC_V2_REDEMPTION =
22 | getEnvVariable(EnvVariable.FEATURE_FLAG_TBTC_V2_REDEMPTION) === "true"
23 |
24 | export const LEDGER_LIVE =
25 | getEnvVariable(EnvVariable.FEATURE_FLAG_LEDGER_LIVE) === "true"
26 |
27 | export const GOOGLE_TAG_MANAGER =
28 | getEnvVariable(EnvVariable.FEATURE_FLAG_GOOGLE_TAG_MANAGER) === "true"
29 |
--------------------------------------------------------------------------------
/src/constants/index.ts:
--------------------------------------------------------------------------------
1 | export * as vendingMachine from "./vendingMachine"
2 | export * as stakingBonus from "./stakingBonus"
3 | export * as web3 from "./web3"
4 | export * as featureFlags from "./featureFlags"
5 |
--------------------------------------------------------------------------------
/src/constants/stakingBonus.ts:
--------------------------------------------------------------------------------
1 | export const STAKING_BONUS_MULTIPLIER = "0.03" // 3%
2 | export const BONUS_DEADLINE_TIMESTAMP = 1654041599 // May 31 2022 23:59:59 GMT
3 | export const REWARDS_DISTRIBUTION_TIMESTAMP = 1657843200 // July 15 2022 00:00:00 GMT
4 | export const BONUS_DEADLINE_BLOCK_NUMBER = 14881676 // https:etherscan.io/block/14881676
5 |
--------------------------------------------------------------------------------
/src/constants/vendingMachine.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from "@ethersproject/bignumber"
2 | import { STANDARD_ERC20_DECIMALS } from "./web3"
3 |
4 | export const WRAPPED_TOKEN_CONVERSION_PRECISION = 3
5 | export const FLOATING_POINT_DIVISOR = BigNumber.from(10).pow(
6 | BigNumber.from(STANDARD_ERC20_DECIMALS - WRAPPED_TOKEN_CONVERSION_PRECISION)
7 | )
8 |
--------------------------------------------------------------------------------
/src/constants/web3.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from "ethers"
2 |
3 | export const STANDARD_ERC20_DECIMALS = 18
4 | export const SATOSHI_MULTIPLIER = BigNumber.from(10).pow(8)
5 | export const ONE_HUNDRED = BigNumber.from(100)
6 |
--------------------------------------------------------------------------------
/src/contexts/StakeCardContext.tsx:
--------------------------------------------------------------------------------
1 | import { createContext } from "react"
2 |
3 | interface StakeCardContext {
4 | isInactiveStake: boolean
5 | canTopUpKepp: boolean
6 | canTopUpNu: boolean
7 | hasLegacyStakes: boolean
8 | }
9 |
10 | export const StakeCardContext = createContext(
11 | undefined
12 | )
13 |
--------------------------------------------------------------------------------
/src/contexts/SuiWalletProvider.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | SuietWallet,
3 | SuiWallet,
4 | MartianWallet,
5 | NightlyWallet,
6 | WalletProvider,
7 | DefaultChains,
8 | SuiTestnetChain,
9 | SuiMainnetChain,
10 | } from "@suiet/wallet-kit"
11 | import { FC, ReactNode } from "react"
12 | import { getEthereumDefaultProviderChainId } from "../utils/getEnvVariable"
13 | import { isMainnetChainId } from "../networks/utils"
14 | interface SuiWalletProviderProps {
15 | children: ReactNode
16 | }
17 |
18 | const SuiWalletProvider: FC = ({ children }) => {
19 | const defaultWallets = [SuietWallet, SuiWallet, MartianWallet, NightlyWallet]
20 | const isMainnet = isMainnetChainId(getEthereumDefaultProviderChainId())
21 |
22 | return (
23 |
27 | {children}
28 |
29 | )
30 | }
31 |
32 | export default SuiWalletProvider
33 |
--------------------------------------------------------------------------------
/src/declaration.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.png"
2 | declare module "*.svg"
3 |
--------------------------------------------------------------------------------
/src/enums/__tests__/web3.test.ts:
--------------------------------------------------------------------------------
1 | import { WalletType } from "../web3"
2 |
3 | describe("WalletType enum", () => {
4 | it("should have STARKNET value", () => {
5 | expect(WalletType.Starknet).toBe("STARKNET")
6 | })
7 |
8 | it("should maintain existing wallet types", () => {
9 | expect(WalletType.TAHO).toBe("TAHO")
10 | expect(WalletType.Metamask).toBe("METAMASK")
11 | expect(WalletType.WalletConnect).toBe("WALLET_CONNECT")
12 | expect(WalletType.Coinbase).toBe("COINBASE")
13 | expect(WalletType.LedgerLive).toBe("LEDGER_LIVE")
14 | })
15 |
16 | it("should have exactly 6 wallet types", () => {
17 | const walletTypes = Object.keys(WalletType)
18 | expect(walletTypes).toHaveLength(6)
19 | })
20 |
21 | it("should maintain backward compatibility", () => {
22 | // Ensure that adding Starknet doesn't break existing usage
23 | const walletType: WalletType = WalletType.Metamask
24 | expect(walletType).toBe("METAMASK")
25 | })
26 | })
27 |
--------------------------------------------------------------------------------
/src/enums/api.ts:
--------------------------------------------------------------------------------
1 | export enum ApiUrl {
2 | TBTC_EXPLORER = "https://api.tbtcscan.com",
3 | THRESHOLD = "https://api.threshold.network",
4 | CURVE = "https://api.curve.fi/api",
5 | COINGECKO = "https://api.coingecko.com/api/v3",
6 | }
7 |
8 | export enum endpointUrl {
9 | TRM_WALLET_SCREENING = "/trm/screen",
10 | CURVE_ETHEREUM_POOL = "/getPools/ethereum/factory",
11 | COINGECKO_SIMPLE_PRICE = "/simple/price",
12 | COINGECKO_VS_CURRENCY = "vs_currencies",
13 | }
14 |
--------------------------------------------------------------------------------
/src/enums/env.ts:
--------------------------------------------------------------------------------
1 | const envVariables = [
2 | "DEFAULT_PROVIDER_CHAIN_ID",
3 | "ALCHEMY_API_KEY",
4 | "TBTC_SUBGRAPH_API_KEY",
5 | "FEATURE_FLAG_TBTC_V2",
6 | "FEATURE_FLAG_TBTC_V2_REDEMPTION",
7 | "FEATURE_FLAG_MULTI_APP_STAKING",
8 | "FEATURE_FLAG_POSTHOG",
9 | "FEATURE_FLAG_FEEDBACK_MODULE",
10 | "FEATURE_FLAG_LEDGER_LIVE",
11 | "FEATURE_FLAG_TRM",
12 | "POSTHOG_HOSTNAME_HTTP",
13 | "POSTHOG_API_KEY",
14 | "ELECTRUM_PROTOCOL",
15 | "ELECTRUM_HOST",
16 | "ELECTRUM_PORT",
17 | "MOCK_BITCOIN_CLIENT",
18 | "FEATURE_FLAG_SENTRY",
19 | "SENTRY_DSN",
20 | "WALLET_CONNECT_PROJECT_ID",
21 | "DAPP_DEVELOPMENT_TESTNET_CONTRACTS",
22 | "FEATURE_FLAG_GOOGLE_TAG_MANAGER",
23 | "GOOGLE_TAG_MANAGER_ID",
24 | ] as const
25 |
26 | export type EnvVariableKey = typeof envVariables[number]
27 |
28 | // In order not to break the previous enum API, so using eg.
29 | // `EnvVariable.ALCHEMY_API_KEY` is still valid.
30 | export const EnvVariable: Record =
31 | envVariables.reduce((reducer, envKey) => {
32 | reducer[envKey] = envKey
33 | return reducer
34 | }, {} as Record)
35 |
--------------------------------------------------------------------------------
/src/enums/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./env"
2 | export * from "./externalHref"
3 | export * from "./modal"
4 | export * from "./pool"
5 | export * from "./staking"
6 | export * from "./token"
7 | export * from "./transactionType"
8 | export * from "./web3"
9 | export * from "./api"
10 |
--------------------------------------------------------------------------------
/src/enums/pool.ts:
--------------------------------------------------------------------------------
1 | export enum CurveFactoryPoolId {
2 | TBTC_WBTC_SBTC = "factory-v2-247",
3 | }
4 |
--------------------------------------------------------------------------------
/src/enums/staking.ts:
--------------------------------------------------------------------------------
1 | // Note: Must be in the same order as here:
2 | // https://github.com/threshold-network/solidity-contracts/blob/main/contracts/staking/IStaking.sol#L26-L30
3 | // because solidity eg. for `StakeType.NU` returns 0.
4 | export enum StakeType {
5 | NU,
6 | KEEP,
7 | T,
8 | }
9 |
10 | export enum UnstakeType {
11 | NATIVE,
12 | LEGACY_KEEP,
13 | LEGACY_NU,
14 | ALL,
15 | }
16 |
17 | export enum TopUpType {
18 | NATIVE,
19 | LEGACY_KEEP,
20 | LEGACY_NU,
21 | }
22 |
--------------------------------------------------------------------------------
/src/enums/token.ts:
--------------------------------------------------------------------------------
1 | export enum Token {
2 | Keep = "KEEP",
3 | Nu = "NU",
4 | T = "T",
5 | TBTC = "TBTC",
6 | TBTCV2 = "TBTCV2",
7 | }
8 |
9 | export enum CoingeckoID {
10 | KEEP = "keep-network",
11 | NU = "nucypher",
12 | T = "threshold-network-token",
13 | ETH = "ethereum",
14 | TBTC = "tbtc",
15 | // TODO: add prope tbtc-v2 id when it lands on coingecko
16 | TBTCV2 = "tbtc",
17 | }
18 |
19 | export enum TConversionRates {
20 | KEEP = 4.87,
21 | NU = 3.46,
22 | T = 1,
23 | }
24 |
--------------------------------------------------------------------------------
/src/enums/transactionType.ts:
--------------------------------------------------------------------------------
1 | export enum TransactionType {
2 | ApproveKeep = "APPROVE_KEEP",
3 | ApproveNu = "APPROVE_NU",
4 | UpgradeKeep = "UPGRADE_KEEP",
5 | UpgradeNu = "UPGRADE_NU",
6 | ApproveT = "APPROVE_T",
7 | }
8 |
9 | export enum TransactionStatus {
10 | Idle = "IDLE",
11 | PendingWallet = "PENDING_WALLET",
12 | PendingOnChain = "PENDING_ON_CHAIN",
13 | Rejected = "REJECTED",
14 | Failed = "FAILED",
15 | Succeeded = "SUCCEEDED",
16 | }
17 |
--------------------------------------------------------------------------------
/src/enums/web3.ts:
--------------------------------------------------------------------------------
1 | export enum ConnectionError {
2 | MetamaskNotInstalled = "No Ethereum provider was found on window.ethereum",
3 | RejectedMetamaskConnection = "The user rejected the request.",
4 | RejectedCoinbaseConnection = "User denied account authorization",
5 | CoinbaseUnsupportedNetwork = "Unsupported chain id:",
6 | }
7 |
8 | export enum WalletType {
9 | TAHO = "TAHO",
10 | Metamask = "METAMASK",
11 | WalletConnect = "WALLET_CONNECT",
12 | Coinbase = "COINBASE",
13 | LedgerLive = "LEDGER_LIVE",
14 | Starknet = "STARKNET",
15 | Sui = "SUI",
16 | }
17 |
18 | export const WALLETS: { [key: string]: WalletType } = {
19 | // ... existing code ...
20 | }
21 |
--------------------------------------------------------------------------------
/src/hooks/__mocks__/useStarknetConnection.ts:
--------------------------------------------------------------------------------
1 | import { UseStarknetConnectionResult } from "../useStarknetConnection"
2 |
3 | export const mockUseStarknetConnection: UseStarknetConnectionResult = {
4 | isConnected: false,
5 | isConnecting: false,
6 | address: null,
7 | provider: null,
8 | walletName: null,
9 | walletIcon: null,
10 | connect: jest.fn().mockResolvedValue(undefined),
11 | disconnect: jest.fn(),
12 | chainId: null,
13 | availableWallets: [],
14 | error: null,
15 | }
16 |
17 | export const useStarknetConnection = jest.fn(
18 | (): UseStarknetConnectionResult => mockUseStarknetConnection
19 | )
20 |
--------------------------------------------------------------------------------
/src/hooks/__tests__/useTExchangeRate.test.ts:
--------------------------------------------------------------------------------
1 | import { renderHook } from "@testing-library/react-hooks"
2 | import { WeiPerEther } from "@ethersproject/constants"
3 | import { useTExchangeRate } from "../useTExchangeRate"
4 | import { useTConvertedAmount } from "../useTConvertedAmount"
5 | import { Token } from "../../enums"
6 |
7 | jest.mock("../useTConvertedAmount", () => ({
8 | useTConvertedAmount: jest.fn(),
9 | }))
10 |
11 | describe("Test `useTExchangeRate` hook", () => {
12 | const token = Token.Keep
13 | const mockedExchangeRate = {
14 | amount: "4500000000000000000",
15 | formattedAmount: "4.5",
16 | }
17 |
18 | beforeEach(() => {
19 | ;(useTConvertedAmount as jest.Mock).mockReturnValue(mockedExchangeRate)
20 | })
21 |
22 | test("should return correct exchange rate", () => {
23 | const { result } = renderHook(() => useTExchangeRate(token))
24 |
25 | expect(useTConvertedAmount).toHaveBeenCalledWith(
26 | token,
27 | WeiPerEther.toString()
28 | )
29 | expect(result.current).toEqual(mockedExchangeRate)
30 | })
31 | })
32 |
--------------------------------------------------------------------------------
/src/hooks/google-tag-manager/index.ts:
--------------------------------------------------------------------------------
1 | export { useGoogleTagManager } from "./useGoogleTagManager"
2 |
--------------------------------------------------------------------------------
/src/hooks/ledger-live-app/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./useRequestBitcoinAccount"
2 | export * from "./useRequestEthereumAccount"
3 | export * from "./useSendBitcoinTransaction"
4 |
--------------------------------------------------------------------------------
/src/hooks/posthog/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./usePosthog"
2 | export * from "./useCapture"
3 |
--------------------------------------------------------------------------------
/src/hooks/posthog/useCapture.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { PosthogEvent } from "../../types/posthog"
3 | import { featureFlags } from "../../constants"
4 | import * as posthog from "../../posthog"
5 |
6 | export const useCapture = (eventName: PosthogEvent) => {
7 | return useCallback(
8 | (params?) => {
9 | if (!featureFlags.POSTHOG) return
10 | posthog.capture(eventName, params)
11 | },
12 | [eventName]
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/src/hooks/posthog/useCapturePageview.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react"
2 | import { useLocation } from "react-router-dom"
3 | import * as posthog from "../../posthog"
4 | import { featureFlags } from "../../constants"
5 |
6 | export const useCapturePageview = () => {
7 | const location = useLocation()
8 |
9 | useEffect(() => {
10 | if (featureFlags.POSTHOG) posthog.capturePageview()
11 | }, [location])
12 | }
13 |
--------------------------------------------------------------------------------
/src/hooks/posthog/usePosthog.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react"
2 | import { featureFlags } from "../../constants"
3 | import * as posthog from "../../posthog"
4 | import { useCapturePageview } from "./useCapturePageview"
5 | import { useCaptureWalletConnectedEvent } from "./useCaptureWalletConnectedEvent"
6 | import { useIdentify } from "./useIdentify"
7 |
8 | export const usePosthog = () => {
9 | useEffect(() => {
10 | if (featureFlags.POSTHOG) {
11 | posthog.init()
12 | }
13 | }, [])
14 |
15 | useCapturePageview()
16 | useIdentify()
17 | useCaptureWalletConnectedEvent()
18 | }
19 |
--------------------------------------------------------------------------------
/src/hooks/sentry/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./useCaptureMessage"
2 | export * from "./useSentry"
3 |
--------------------------------------------------------------------------------
/src/hooks/sentry/useCaptureMessage.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { featureFlags } from "../../constants"
3 | import * as sentry from "../../sentry"
4 | import { Primitive } from "@sentry/types"
5 |
6 | export const useCaptureMessage = () => {
7 | return useCallback(
8 | (
9 | message: string,
10 | params?: { [key: string]: unknown },
11 | tags?: { [key: string]: Primitive }
12 | ) => {
13 | if (!featureFlags.SENTRY) return
14 | sentry.captureMessage(message, params, tags)
15 | },
16 | []
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/src/hooks/sentry/useSentry.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react"
2 | import { featureFlags } from "../../constants"
3 | import * as sentry from "../../sentry"
4 |
5 | export const useSentry = () => {
6 | useEffect(() => {
7 | if (featureFlags.SENTRY) {
8 | sentry.init()
9 | }
10 | }, [])
11 | }
12 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./useStakingAppContract"
2 | export * from "./useStakingAppDataByStakingProvider"
3 | export * from "./useStakingApplicationState"
4 | export * from "./useStakingAppMinAuthorizationAmount"
5 | export * from "./useStakingAppParameters"
6 | export * from "./useSubscribeToAuthorizationIncreasedEvent"
7 | export * from "./useAuthorizeMultipleAppsTransaction"
8 | export * from "./useIncreaseAuthorizationTransaction"
9 | export * from "./useStakingApplicationAddress"
10 | export * from "./useSubscribeToAuthorizationDecreaseApprovedEvent"
11 | export * from "./useConfirmDeauthorizationTransaction"
12 | export * from "./useInitiateDeauthorization"
13 | export * from "./useSubscribeToAuthorizationDecreaseRequestedEvent"
14 | export * from "./useStakingApplicationDecreaseDelay"
15 | export * from "./useSubscribeToOperatorRegisteredEvent"
16 | export * from "./useUpdateOperatorStatus"
17 | export * from "./useSubscribeToOperatorStatusUpdatedEvent"
18 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useBondOperatorTransaction.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import { StakingAppName } from "../../store/staking-applications"
3 | import { Application } from "../../threshold-ts/applications"
4 | import {
5 | OnErrorCallback,
6 | OnSuccessCallback,
7 | useSendTransactionFromFn,
8 | } from "../../web3/hooks"
9 | import { appNameToThresholdApp } from "./useStakingAppContract"
10 |
11 | export const useBondOperatorTransaction = (
12 | appName: StakingAppName,
13 | onSuccess?: OnSuccessCallback,
14 | onError?: OnErrorCallback
15 | ) => {
16 | const threshold = useThreshold()
17 |
18 | return useSendTransactionFromFn(
19 | (threshold.multiAppStaking[appNameToThresholdApp[appName]] as Application)
20 | ?.bondOperator,
21 | onSuccess,
22 | onError
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useConfirmDeauthorizationTransaction.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import { StakingAppName } from "../../store/staking-applications"
3 | import {
4 | OnErrorCallback,
5 | OnSuccessCallback,
6 | useSendTransactionFromFn,
7 | } from "../../web3/hooks"
8 | import { appNameToThresholdApp } from "./useStakingAppContract"
9 |
10 | export const useConfirmDeauthorizationTransaction = (
11 | appName: StakingAppName,
12 | onSuccess?: OnSuccessCallback,
13 | onError?: OnErrorCallback
14 | ) => {
15 | const threshold = useThreshold()
16 |
17 | return useSendTransactionFromFn(
18 | threshold.multiAppStaking[appNameToThresholdApp[appName]]
19 | ?.approveAuthorizationDecrease!,
20 | onSuccess,
21 | onError
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useIncreaseAuthorizationTransaction.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import { StakingAppName } from "../../store/staking-applications"
3 | import {
4 | OnErrorCallback,
5 | OnSuccessCallback,
6 | useSendTransactionFromFn,
7 | } from "../../web3/hooks"
8 | import { appNameToThresholdApp } from "./useStakingAppContract"
9 |
10 | export const useIncreaseAuthorizationTransaction = (
11 | appName: StakingAppName,
12 | onSuccess?: OnSuccessCallback,
13 | onError?: OnErrorCallback
14 | ) => {
15 | const threshold = useThreshold()
16 |
17 | return useSendTransactionFromFn(
18 | threshold.multiAppStaking[appNameToThresholdApp[appName]]
19 | ?.increaseAuthorization!,
20 | onSuccess,
21 | onError
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useRegisterOperatorTransaction.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import { StakingAppName } from "../../store/staking-applications"
3 | import {
4 | OnErrorCallback,
5 | OnSuccessCallback,
6 | useSendTransactionFromFn,
7 | } from "../../web3/hooks"
8 | import { appNameToThresholdApp } from "./useStakingAppContract"
9 |
10 | export const useRegisterOperatorTransaction = (
11 | appName: StakingAppName,
12 | onSuccess?: OnSuccessCallback,
13 | onError?: OnErrorCallback
14 | ) => {
15 | const threshold = useThreshold()
16 |
17 | return useSendTransactionFromFn(
18 | threshold.multiAppStaking[appNameToThresholdApp[appName]]
19 | ?.registerOperator!,
20 | onSuccess,
21 | onError
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useStakingAppContract.ts:
--------------------------------------------------------------------------------
1 | import { StakingAppName } from "../../store/staking-applications"
2 | import { useThreshold } from "../../contexts/ThresholdContext"
3 | import { Contract } from "ethers"
4 |
5 | export const appNameToThresholdApp: Record<
6 | StakingAppName,
7 | "ecdsa" | "randomBeacon" | "taco"
8 | > = {
9 | tbtc: "ecdsa",
10 | randomBeacon: "randomBeacon",
11 | taco: "taco",
12 | }
13 |
14 | export const useStakingAppContract = (appName: StakingAppName): Contract => {
15 | const threshold = useThreshold()
16 |
17 | return threshold.multiAppStaking[appNameToThresholdApp[appName]]?.contract!
18 | }
19 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useStakingAppDataByStakingProvider.ts:
--------------------------------------------------------------------------------
1 | import {
2 | selectStakingAppByStakingProvider,
3 | StakingAppName,
4 | } from "../../store/staking-applications"
5 | import { useAppSelector } from "../store"
6 |
7 | export const useStakingAppDataByStakingProvider = (
8 | appName: StakingAppName,
9 | stakingProvider: string
10 | ) => {
11 | return useAppSelector((state) =>
12 | selectStakingAppByStakingProvider(state, appName, stakingProvider)
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useStakingAppMinAuthorizationAmount.ts:
--------------------------------------------------------------------------------
1 | import { StakingAppName } from "../../store/staking-applications"
2 | import { useStakingAppParameters } from "./useStakingAppParameters"
3 |
4 | export const useStakingAppMinAuthorizationAmount = (
5 | appName: StakingAppName
6 | ) => {
7 | return useStakingAppParameters(appName).data.minimumAuthorization
8 | }
9 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useStakingAppParameters.ts:
--------------------------------------------------------------------------------
1 | import { StakingAppName } from "../../store/staking-applications"
2 | import { useStakingApplicationState } from "./useStakingApplicationState"
3 |
4 | export const useStakingAppParameters = (appName: StakingAppName) => {
5 | return useStakingApplicationState(appName)?.parameters
6 | }
7 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useStakingApplicationAddress.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import { StakingAppName } from "../../store/staking-applications"
3 | import { AddressZero } from "../../web3/utils"
4 | import { appNameToThresholdApp } from "./useStakingAppContract"
5 |
6 | export const useStakingApplicationAddress = (appName: StakingAppName) => {
7 | const threshold = useThreshold()
8 |
9 | return (
10 | threshold.multiAppStaking[appNameToThresholdApp[appName]]?.address ??
11 | AddressZero
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useStakingApplicationDecreaseDelay.ts:
--------------------------------------------------------------------------------
1 | import { StakingAppName } from "../../store/staking-applications"
2 | import { useStakingAppParameters } from "./useStakingAppParameters"
3 |
4 | export const useStakingApplicationDecreaseDelay = (appName: StakingAppName) => {
5 | return useStakingAppParameters(appName)?.data?.authorizationDecreaseDelay
6 | }
7 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useStakingApplicationState.ts:
--------------------------------------------------------------------------------
1 | import {
2 | StakingAppName,
3 | selectStakingAppStateByAppName,
4 | } from "../../store/staking-applications"
5 | import { useAppSelector } from "../store"
6 |
7 | export const useStakingApplicationState = (appName: StakingAppName) => {
8 | return useAppSelector((state) =>
9 | selectStakingAppStateByAppName(state, appName)
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useSubscribeToAuthorizationDecreaseApprovedEvent.ts:
--------------------------------------------------------------------------------
1 | import { Event } from "@ethersproject/contracts"
2 | import {
3 | stakingApplicationsSlice,
4 | StakingAppName,
5 | } from "../../store/staking-applications"
6 | import { useSubscribeToContractEvent } from "../../web3/hooks"
7 | import { useAppDispatch } from "../store"
8 | import { useStakingAppContract } from "./useStakingAppContract"
9 |
10 | export const useSubscribeToAuthorizationDecreaseApprovedEvent = (
11 | appName: StakingAppName
12 | ) => {
13 | const contract = useStakingAppContract(appName)
14 | const dispatch = useAppDispatch()
15 |
16 | useSubscribeToContractEvent(
17 | contract,
18 | "AuthorizationDecreaseApproved",
19 | // @ts-ignore
20 | async (stakingProvider: string, event: Event) => {
21 | dispatch(
22 | stakingApplicationsSlice.actions.authorizationDecreaseApproved({
23 | stakingProvider,
24 | appName,
25 | txHash: event.transactionHash,
26 | })
27 | )
28 | }
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useSubscribeToAuthorizationIncreasedEvent.ts:
--------------------------------------------------------------------------------
1 | import { stakingApplicationsSlice } from "../../store/staking-applications"
2 | import { getStakingAppNameFromAppAddress } from "../../utils/getStakingAppLabel"
3 | import {
4 | useSubscribeToContractEvent,
5 | useTStakingContract,
6 | } from "../../web3/hooks"
7 | import { useAppDispatch } from "../store"
8 |
9 | export const useSubscribeToAuthorizationIncreasedEvent = () => {
10 | const contract = useTStakingContract()
11 | const dispatch = useAppDispatch()
12 |
13 | useSubscribeToContractEvent(
14 | contract,
15 | "AuthorizationIncreased",
16 | // @ts-ignore
17 | async (stakingProvider, application, fromAmount, toAmount) => {
18 | const appName = getStakingAppNameFromAppAddress(application)
19 |
20 | if (!appName) {
21 | console.warn(
22 | `Could not determine staking app name for address: ${application}`
23 | )
24 | return
25 | }
26 |
27 | dispatch(
28 | stakingApplicationsSlice.actions.authorizationIncreased({
29 | stakingProvider,
30 | toAmount: toAmount.toString(),
31 | appName,
32 | })
33 | )
34 | }
35 | )
36 | }
37 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useSubscribeToOperatorRegisteredEvent.ts:
--------------------------------------------------------------------------------
1 | import { useWeb3React } from "@web3-react/core"
2 | import { operatorRegistered } from "../../store/account"
3 | import { StakingAppName } from "../../store/staking-applications"
4 | import { useSubscribeToContractEvent } from "../../web3/hooks"
5 | import { isSameETHAddress } from "../../web3/utils"
6 | import { useAppDispatch } from "../store"
7 | import { useStakingAppContract } from "./useStakingAppContract"
8 |
9 | export const useSubscribeToOperatorRegisteredEvent = (
10 | appName: StakingAppName
11 | ) => {
12 | const contract = useStakingAppContract(appName)
13 | const dispatch = useAppDispatch()
14 | const { account } = useWeb3React()
15 |
16 | useSubscribeToContractEvent(
17 | contract,
18 | "OperatorRegistered",
19 | //@ts-ignore
20 | async (stakingProvider: string, operator: string) => {
21 | if (account && isSameETHAddress(stakingProvider, account)) {
22 | dispatch(
23 | operatorRegistered({
24 | appName,
25 | operator,
26 | })
27 | )
28 | }
29 | },
30 | [account]
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useSubscribeToOperatorStatusUpdatedEvent.ts:
--------------------------------------------------------------------------------
1 | import { Event } from "ethers"
2 | import {
3 | stakingApplicationsSlice,
4 | StakingAppName,
5 | } from "../../store/staking-applications"
6 | import { useSubscribeToContractEvent } from "../../web3/hooks"
7 | import { useAppDispatch } from "../store"
8 | import { useStakingAppContract } from "./useStakingAppContract"
9 |
10 | export const useSubscribeToOperatorStatusUpdatedEvent = (
11 | appName: StakingAppName
12 | ) => {
13 | const contract = useStakingAppContract(appName)
14 | const dispatch = useAppDispatch()
15 |
16 | useSubscribeToContractEvent(
17 | contract,
18 | "OperatorStatusUpdated",
19 | // @ts-ignore
20 | async (stakingProvider: string, operator: string, event: Event) => {
21 | const txHash = event.transactionHash
22 | dispatch(
23 | stakingApplicationsSlice.actions.operatorStatusUpdated({
24 | stakingProvider,
25 | appName,
26 | txHash,
27 | })
28 | )
29 | }
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/src/hooks/staking-applications/useUpdateOperatorStatus.tsx:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import { StakingAppName } from "../../store/staking-applications"
3 | import { useSendTransactionFromFn } from "../../web3/hooks"
4 | import { appNameToThresholdApp } from "./useStakingAppContract"
5 |
6 | export const useUpdateOperatorStatus = (appName: StakingAppName) => {
7 | const threshold = useThreshold()
8 |
9 | return useSendTransactionFromFn(
10 | threshold.multiAppStaking[appNameToThresholdApp[appName]]
11 | ?.updateOperatorStatus!
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/src/hooks/store/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./useAppDispatch"
2 | export * from "./useAppSelector"
3 |
--------------------------------------------------------------------------------
/src/hooks/store/useAppDispatch.ts:
--------------------------------------------------------------------------------
1 | import { useDispatch } from "react-redux"
2 | import { AppDispatch } from "../../store"
3 |
4 | export const useAppDispatch: () => AppDispatch = useDispatch
5 |
--------------------------------------------------------------------------------
/src/hooks/store/useAppSelector.ts:
--------------------------------------------------------------------------------
1 | import { useSelector, TypedUseSelectorHook } from "react-redux"
2 | import { RootState } from "../../store"
3 |
4 | export const useAppSelector: TypedUseSelectorHook = useSelector
5 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./useFetchDepositDetails"
2 | export * from "./useFetchRecentDeposits"
3 | export * from "./useFetchTBTCMetrics"
4 | export * from "./useRedemptionEstimatedFees"
5 | export * from "./useRequestRedemption"
6 | export * from "./useRevealDepositTransaction"
7 | export * from "./useSubscribeToOptimisticMintingFinalizedEvent"
8 | export * from "./useSubscribeToOptimisticMintingRequestedEvent"
9 | export * from "./useSubscribeToRedemptionRequestedEvent"
10 | export * from "./useSubsribeToDepositRevealedEvent"
11 | export * from "./useTBTCDepositDataFromLocalStorage"
12 | export * from "./useTBTCVaultContract"
13 | export * from "./useSubscribeToRedemptionsCompletedEvent"
14 | export * from "./useFindRedemptionInBitcoinTx"
15 | export * from "./useStarknetTBTCBalance"
16 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/useBridgeContract.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 |
3 | export const useBridgeContract = () => {
4 | const threshold = useThreshold()
5 |
6 | return threshold.tbtc.bridgeContract
7 | }
8 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/useRedemptionEstimatedFees.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react"
2 | import { useThreshold } from "../../contexts/ThresholdContext"
3 |
4 | export const useRedemptionEstimatedFees = (unmintedAmount: string) => {
5 | const threshold = useThreshold()
6 | const [estimatedBTCAmount, setEstimatedBTCAmount] = useState<
7 | string | undefined
8 | >(undefined)
9 | const [thresholdNetworkFee, setThresholdNetworkFee] = useState<
10 | string | undefined
11 | >(undefined)
12 |
13 | useEffect(() => {
14 | const getEstimatedRedemptionFees = async () => {
15 | const { treasuryFee, estimatedAmountToBeReceived } =
16 | await threshold.tbtc.getEstimatedRedemptionFees(unmintedAmount)
17 |
18 | setThresholdNetworkFee(treasuryFee)
19 | setEstimatedBTCAmount(estimatedAmountToBeReceived)
20 | }
21 |
22 | getEstimatedRedemptionFees()
23 | }, [unmintedAmount, threshold])
24 |
25 | return { estimatedBTCAmount, thresholdNetworkFee }
26 | }
27 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/useRemoveDepositData.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { useThreshold } from "../../contexts/ThresholdContext"
3 | import { useTbtcState } from "../useTbtcState"
4 | import { useTBTCDepositDataFromLocalStorage } from "./useTBTCDepositDataFromLocalStorage"
5 | import { useIsActive } from "../useIsActive"
6 | import { useNonEVMConnection } from "../useNonEVMConnection"
7 | import { getEthereumNetworkNameFromChainId } from "../../networks/utils"
8 |
9 | export const useRemoveDepositData = () => {
10 | const { chainId } = useIsActive()
11 | const { nonEVMChainName } = useNonEVMConnection()
12 | const { resetDepositData } = useTbtcState()
13 | const { removeDepositDataFromLocalStorage } =
14 | useTBTCDepositDataFromLocalStorage()
15 | const threshold = useThreshold()
16 | const networkName =
17 | nonEVMChainName ?? getEthereumNetworkNameFromChainId(chainId)
18 |
19 | return useCallback(() => {
20 | removeDepositDataFromLocalStorage(networkName)
21 | resetDepositData()
22 | threshold.tbtc.removeDepositData()
23 | }, [resetDepositData, removeDepositDataFromLocalStorage, threshold])
24 | }
25 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/useRequestRedemption.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import {
3 | OnErrorCallback,
4 | OnSuccessCallback,
5 | useSendTransactionFromFn,
6 | } from "../../web3/hooks"
7 |
8 | export const useRequestRedemption = (
9 | onSuccess?: OnSuccessCallback,
10 | onError?: OnErrorCallback
11 | ) => {
12 | const threshold = useThreshold()
13 | const pendingText =
14 | "Searching for an active wallet with sufficient funds to proceed with your unmint. Please wait for the transaction prompt, and then sign in your wallet."
15 |
16 | return useSendTransactionFromFn(
17 | threshold.tbtc.requestRedemption,
18 | onSuccess,
19 | onError,
20 | pendingText
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/useRevealDepositTransaction.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 | import {
3 | OnErrorCallback,
4 | OnSuccessCallback,
5 | useSendTransactionFromFn,
6 | } from "../../web3/hooks"
7 | import { useNonEVMConnection } from "../useNonEVMConnection"
8 |
9 | export const useRevealDepositTransaction = (
10 | onSuccess?: OnSuccessCallback,
11 | onError?: OnErrorCallback
12 | ) => {
13 | const threshold = useThreshold()
14 | const { nonEVMPublicKey } = useNonEVMConnection()
15 | const pendingText = nonEVMPublicKey
16 | ? "Please wait for the transaction to be confirmed"
17 | : "Please confirm the transaction in your wallet"
18 |
19 | return useSendTransactionFromFn(
20 | threshold.tbtc.revealDeposit,
21 | onSuccess,
22 | onError,
23 | pendingText
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/useSubscribeToRedemptionsCompletedEvent.ts:
--------------------------------------------------------------------------------
1 | // TODO: Refactor this so that it's only imported in our threshold-ts lib
2 | import { Hex } from "@keep-network/tbtc-v2.ts"
3 | import { Event } from "ethers"
4 | import { useSubscribeToContractEvent } from "../../web3/hooks"
5 | import { useBridgeContract } from "./useBridgeContract"
6 |
7 | type RedemptionsCompletedEventCallback = (
8 | walletPublicKeyHash: string,
9 | redemptionTxHash: string,
10 | event: Event
11 | ) => void
12 |
13 | export const useSubscribeToRedemptionsCompletedEventBase = (
14 | callback: RedemptionsCompletedEventCallback,
15 | filterParams?: any[],
16 | shouldSubscribeIfUserNotConnected: boolean = false
17 | ) => {
18 | const tBTCBridgeContract = useBridgeContract()
19 |
20 | useSubscribeToContractEvent(
21 | tBTCBridgeContract,
22 | "RedemptionsCompleted",
23 | //@ts-ignore
24 | (walletPublicKeyHash, redemptionTxHash, event) => {
25 | callback(
26 | walletPublicKeyHash,
27 | Hex.from(redemptionTxHash).reverse().toString(),
28 | event
29 | )
30 | },
31 | filterParams,
32 | shouldSubscribeIfUserNotConnected
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/src/hooks/tbtc/useTBTCVaultContract.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 |
3 | export const useTBTCVaultContract = () => {
4 | return useThreshold().tbtc.vaultContract
5 | }
6 |
--------------------------------------------------------------------------------
/src/hooks/useAnalytics.ts:
--------------------------------------------------------------------------------
1 | import { useLocalStorage } from "./useLocalStorage"
2 | import { useCallback } from "react"
3 |
4 | export const useAnalytics = () => {
5 | const [isAnalyticsEnabled, setIsAnalyticsEnabled] = useLocalStorage<
6 | boolean | undefined
7 | >("isAnalyticsEnabled", undefined)
8 |
9 | const enableAnalytics = useCallback(() => {
10 | setIsAnalyticsEnabled(true)
11 | }, [setIsAnalyticsEnabled])
12 |
13 | const disableAnalytics = useCallback(() => {
14 | setIsAnalyticsEnabled(false)
15 | }, [setIsAnalyticsEnabled])
16 |
17 | return {
18 | isAnalyticsEnabled,
19 | hasUserResponded: typeof isAnalyticsEnabled === "boolean",
20 | enableAnalytics,
21 | disableAnalytics,
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/hooks/useConnectWallet.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { ModalType } from "../enums"
3 | import { useRequestEthereumAccount } from "./ledger-live-app"
4 | import { useIsEmbed } from "./useIsEmbed"
5 | import { useModal } from "./useModal"
6 |
7 | export const useConnectWallet = (): (() => void) => {
8 | const { isEmbed } = useIsEmbed()
9 | const { requestAccount } = useRequestEthereumAccount()
10 | const { openModal } = useModal()
11 |
12 | return useCallback(() => {
13 | if (isEmbed) {
14 | requestAccount()
15 | } else {
16 | openModal(ModalType.SelectWallet)
17 | }
18 | }, [isEmbed, requestAccount])
19 | }
20 |
--------------------------------------------------------------------------------
/src/hooks/useDocumentTitle.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react"
2 |
3 | const useDocumentTitle = (title: string) => {
4 | useEffect(() => {
5 | document.title = title
6 | }, [title])
7 | }
8 |
9 | export default useDocumentTitle
10 |
--------------------------------------------------------------------------------
/src/hooks/useETHData.ts:
--------------------------------------------------------------------------------
1 | import { useSelector } from "react-redux"
2 | import { RootState } from "../store"
3 | import { EthStateData } from "../types"
4 |
5 | export const useETHData = (): EthStateData => {
6 | return useSelector((state: RootState) => state.eth)
7 | }
8 |
--------------------------------------------------------------------------------
/src/hooks/useIsEmbed.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { useLocalStorage } from "./useLocalStorage"
3 |
4 | export const useIsEmbed = () => {
5 | const [isEmbed, setIsEmbed] = useLocalStorage(
6 | "isEmbed",
7 | undefined
8 | )
9 |
10 | const enableIsEmbed = useCallback(() => {
11 | setIsEmbed(true)
12 | }, [setIsEmbed])
13 |
14 | const disableIsEmbed = useCallback(() => {
15 | setIsEmbed(false)
16 | }, [setIsEmbed])
17 |
18 | return {
19 | enableIsEmbed,
20 | disableIsEmbed,
21 | isEmbed,
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/hooks/useLocalStorage.ts:
--------------------------------------------------------------------------------
1 | import { useLocalStorage as useRehooksLocalStorage } from "@rehooks/local-storage"
2 |
3 | export const useLocalStorage = (key: string, defaultValue: T) => {
4 | return useRehooksLocalStorage(key, defaultValue)
5 | }
6 |
--------------------------------------------------------------------------------
/src/hooks/useNextRewardsDropDate.ts:
--------------------------------------------------------------------------------
1 | import { dateToUnixTimestamp } from "@threshold-network/components"
2 |
3 | export const useNextRewardsDropDate = () => {
4 | const today = new Date()
5 | const year = today.getFullYear()
6 | const month = today.getMonth()
7 |
8 | return dateToUnixTimestamp(
9 | month === 11 ? new Date(year + 1, 0, 1) : new Date(year, month + 1, 1)
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/src/hooks/useSaveConnectedAddressToStore.ts:
--------------------------------------------------------------------------------
1 | import { useWeb3React } from "@web3-react/core"
2 | import { useEffect } from "react"
3 | import { useDispatch } from "react-redux"
4 | import { walletConnected } from "../store/account"
5 |
6 | export const useSaveConnectedAddressToStore = () => {
7 | const { account, chainId } = useWeb3React()
8 | const dispatch = useDispatch()
9 |
10 | useEffect(() => {
11 | const address = account ? account : ""
12 | dispatch(walletConnected({ address, chainId }))
13 | }, [account])
14 | }
15 |
--------------------------------------------------------------------------------
/src/hooks/useSidebar.ts:
--------------------------------------------------------------------------------
1 | import { useDispatch, useSelector } from "react-redux"
2 | import { UseSidebar } from "../types"
3 | import {
4 | closeSidebar as closeSidebarAction,
5 | openSidebar as openSidebarAction,
6 | } from "../store/sidebar"
7 | import { RootState } from "../store"
8 |
9 | export const useSidebar: UseSidebar = () => {
10 | const isOpen = useSelector((state: RootState) => state.sidebar.isOpen)
11 | const dispatch = useDispatch()
12 |
13 | const openSidebar = () => dispatch(openSidebarAction())
14 | const closeSidebar = () => dispatch(closeSidebarAction())
15 |
16 | return {
17 | isOpen,
18 | openSidebar,
19 | closeSidebar,
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/hooks/useStakeCardContext.ts:
--------------------------------------------------------------------------------
1 | import { useContext } from "react"
2 | import { StakeCardContext } from "../contexts/StakeCardContext"
3 |
4 | export const useStakeCardContext = () => {
5 | const stakeCardContext = useContext(StakeCardContext)
6 |
7 | if (!stakeCardContext) {
8 | throw new Error("StakeCardContext used outside of the StakeCard component.")
9 | }
10 |
11 | return stakeCardContext
12 | }
13 |
--------------------------------------------------------------------------------
/src/hooks/useStakingState.ts:
--------------------------------------------------------------------------------
1 | import { useSelector, useDispatch } from "react-redux"
2 | import { updateState as updateStateAction } from "../store/staking"
3 | import { RootState } from "../store"
4 | import { StakingStateKey, UseStakingState } from "../types/staking"
5 |
6 | export const useStakingState: UseStakingState = () => {
7 | const stakingState = useSelector((state: RootState) => state.staking)
8 | const dispatch = useDispatch()
9 |
10 | const updateState = (key: StakingStateKey, value: any) =>
11 | dispatch(updateStateAction({ key, value }))
12 |
13 | return {
14 | ...stakingState,
15 | updateState,
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/hooks/useTBTCBridgeContractAddress.ts:
--------------------------------------------------------------------------------
1 | import { useBridgeContract } from "./tbtc/useBridgeContract"
2 |
3 | export const useTBTCBridgeContractAddress = () => {
4 | const bridgeContract = useBridgeContract()
5 |
6 | return bridgeContract?.address
7 | }
8 |
--------------------------------------------------------------------------------
/src/hooks/useTBTCTerms.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { useLocalStorage } from "./useLocalStorage"
3 |
4 | export const useTBTCTerms = () => {
5 | const [haveTermsBeenAccepted, setHaveTermsBeenAccepted] = useLocalStorage<
6 | boolean | undefined
7 | >("tBTCTerms", undefined)
8 |
9 | const accept = useCallback(() => {
10 | setHaveTermsBeenAccepted(true)
11 | }, [setHaveTermsBeenAccepted])
12 |
13 | const reject = useCallback(() => {
14 | setHaveTermsBeenAccepted(false)
15 | }, [setHaveTermsBeenAccepted])
16 |
17 | return {
18 | accept,
19 | reject,
20 | haveTermsBeenAccepted,
21 | hasUserResponded: typeof haveTermsBeenAccepted === "boolean",
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/hooks/useTBTCTokenAddress.ts:
--------------------------------------------------------------------------------
1 | import { useTBTCv2TokenContract } from "../web3/hooks/useTBTCv2TokenContract"
2 |
3 | export const useTBTCTokenAddress = () => {
4 | const tbtcContract = useTBTCv2TokenContract()
5 |
6 | return tbtcContract?.contract?.address
7 | }
8 |
--------------------------------------------------------------------------------
/src/hooks/useTExchangeRate.ts:
--------------------------------------------------------------------------------
1 | import { WeiPerEther } from "@ethersproject/constants"
2 | import { useTConvertedAmount } from "./useTConvertedAmount"
3 | import { UpgredableToken } from "../types"
4 |
5 | export const useTExchangeRate = (token: UpgredableToken) => {
6 | return useTConvertedAmount(token, WeiPerEther.toString())
7 | }
8 |
--------------------------------------------------------------------------------
/src/hooks/useToken.ts:
--------------------------------------------------------------------------------
1 | import { useContext } from "react"
2 | import { TokenContext } from "../contexts/TokenContext"
3 | import { Token } from "../enums"
4 |
5 | export const useToken = (token: Token) => {
6 | const tokenContext = useContext(TokenContext)
7 |
8 | return tokenContext[token]
9 | }
10 |
--------------------------------------------------------------------------------
/src/hooks/useTokenBalance.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react"
2 | import { Token } from "../enums/token"
3 | import { useToken } from "./useToken"
4 |
5 | export const useTokenBalance = (token: Token) => {
6 | const _token = useToken(token)
7 |
8 | return useMemo(() => _token.balance, [_token.balance])
9 | }
10 |
--------------------------------------------------------------------------------
/src/hooks/useTokensBalanceCall.ts:
--------------------------------------------------------------------------------
1 | import { Contract } from "@ethersproject/contracts"
2 | import { useMulticall } from "../web3/hooks/useMulticall"
3 |
4 | export const useTokensBalanceCall = (tokens: Contract[], address: string) => {
5 | return useMulticall(
6 | tokens.map((tokenContract) => ({
7 | address: tokenContract?.address,
8 | interface: tokenContract?.interface,
9 | method: "balanceOf",
10 | args: [address],
11 | }))
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/src/hooks/useUpgradeHref.ts:
--------------------------------------------------------------------------------
1 | import { useWeb3React } from "@web3-react/core"
2 | import { BigNumber } from "ethers"
3 | import { useTokenState } from "./useTokenState"
4 | import { useEffect, useState } from "react"
5 |
6 | const useUpgradeHref = () => {
7 | const { keep, nu } = useTokenState()
8 | const { active } = useWeb3React()
9 |
10 | const [upgradeHref, setUpgradeHref] = useState("/upgrade")
11 |
12 | useEffect(() => {
13 | const keepBalanceBn = BigNumber.from(keep.balance)
14 | const nuBalanceBn = BigNumber.from(nu.balance)
15 |
16 | if (active) {
17 | if (keepBalanceBn.gt(nuBalanceBn)) {
18 | setUpgradeHref("/upgrade/keep")
19 | } else {
20 | setUpgradeHref("/upgrade/nu")
21 | }
22 | }
23 | }, [active, keep.balance, nu.balance])
24 |
25 | return upgradeHref
26 | }
27 |
28 | export default useUpgradeHref
29 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import ReactDOM from "react-dom"
3 | import App from "./App"
4 | import TransportProvider from "./contexts/TransportProvider"
5 |
6 | ReactDOM.render(
7 |
8 |
9 |
10 |
11 | ,
12 | document.getElementById("root")
13 | )
14 |
--------------------------------------------------------------------------------
/src/networks/constants/networks.ts:
--------------------------------------------------------------------------------
1 | export const DECIMALS = 18
2 | export const ETH_SYMBOL = "ETH"
3 |
--------------------------------------------------------------------------------
/src/networks/hooks/useConnectedOrDefaultEthereumChainId.ts:
--------------------------------------------------------------------------------
1 | import { useIsActive } from "../../hooks/useIsActive"
2 | import { getEthereumDefaultProviderChainId } from "../../utils/getEnvVariable"
3 | import { isMainnetChainId } from "../utils"
4 |
5 | export const useConnectedOrDefaultEthereumChainId = () => {
6 | const { chainId } = useIsActive()
7 | const defaultEthereumChainId = getEthereumDefaultProviderChainId()
8 |
9 | // If no chain is connected, use the default chain.
10 | if (!chainId) return defaultEthereumChainId
11 |
12 | const isActiveMainnet = isMainnetChainId(chainId)
13 | const isDefaultMainnet = isMainnetChainId(defaultEthereumChainId)
14 |
15 | // Return the connected chainId if it matches the default provider’s network type.
16 | return isActiveMainnet === isDefaultMainnet ? chainId : defaultEthereumChainId
17 | }
18 |
--------------------------------------------------------------------------------
/src/networks/types/networks.ts:
--------------------------------------------------------------------------------
1 | import { Chains } from "@keep-network/tbtc-v2.ts"
2 | import {
3 | Layer,
4 | NetworkType,
5 | SupportedChainIds,
6 | AlchemyName,
7 | } from "../enums/networks"
8 |
9 | export interface NetworksAlchemyConfig {
10 | [chainId: number]: {
11 | name: AlchemyName
12 | type: NetworkType
13 | }
14 | }
15 |
16 | export interface EthereumRpcMap {
17 | [chainId: string]: string
18 | }
19 |
20 | export type NetworkName = keyof typeof SupportedChainIds
21 | export type MainNetworkName = keyof typeof Chains
22 | export interface Network {
23 | chainId: SupportedChainIds
24 | name: Exclude
25 | layer: Layer
26 | networkType: NetworkType
27 | chainParameters: {
28 | chainId: string
29 | chainName: string
30 | nativeCurrency: {
31 | name: string
32 | symbol: string
33 | decimals: number
34 | }
35 | rpcUrls: string[]
36 | blockExplorerUrls: string[]
37 | }
38 | alchemyName?: AlchemyName
39 | }
40 |
41 | export type NetworkMapping = Record
42 |
--------------------------------------------------------------------------------
/src/networks/utils/chainId.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber, ethers } from "ethers"
2 |
3 | export const toHex = (value: string | number): string =>
4 | ethers.utils.hexValue(ethers.BigNumber.from(value))
5 |
6 | export const hexToNumber = (value: string | number): number => {
7 | if (typeof value === "number") {
8 | return value
9 | }
10 | if (typeof value === "string" && value.startsWith("0x")) {
11 | return ethers.BigNumber.from(value).toNumber()
12 | }
13 |
14 | return parseInt(value)
15 | }
16 |
17 | export const isSameChainNameOrId = (
18 | a: string | number | undefined,
19 | b: string | number | undefined
20 | ): boolean => {
21 | if (a === undefined || b === undefined) return false
22 |
23 | // both numeric → safe BigNumber comparison
24 | if (!isNaN(+a) && !isNaN(+b)) {
25 | return BigNumber.from(a).eq(BigNumber.from(b))
26 | }
27 |
28 | // at least one side is not numeric → do case-insensitive string compare
29 | return String(a).toLowerCase() === String(b).toLowerCase()
30 | }
31 |
--------------------------------------------------------------------------------
/src/networks/utils/getMainnetOrTestnetChainId.ts:
--------------------------------------------------------------------------------
1 | import { SupportedChainIds } from "../enums/networks"
2 | import { isTestnetChainId } from "../utils"
3 |
4 | export const getMainnetOrTestnetChainId = (chainId?: number | string) => {
5 | return chainId && isTestnetChainId(chainId)
6 | ? SupportedChainIds.Sepolia
7 | : SupportedChainIds.Ethereum
8 | }
9 |
--------------------------------------------------------------------------------
/src/networks/utils/getRpcUrl.ts:
--------------------------------------------------------------------------------
1 | import { EnvVariable } from "../../enums"
2 | import {
3 | getEthereumDefaultProviderChainId,
4 | getEnvVariable,
5 | } from "../../utils/getEnvVariable"
6 | import { SupportedChainIds } from "../enums/networks"
7 | import { networksAlchemyConfig } from "./networksAlchemyConfig"
8 |
9 | const MAIN_ALCHEMY_URL = "g.alchemy.com/v2/"
10 |
11 | export const getRpcUrl = (chainId?: number | string) => {
12 | const alchemyApiKey = getEnvVariable(EnvVariable.ALCHEMY_API_KEY)
13 | const defaultChainId = getEthereumDefaultProviderChainId()
14 | const chainIdNum = Number(chainId) || defaultChainId
15 | const alchemyConfig = networksAlchemyConfig[chainIdNum as SupportedChainIds]
16 |
17 | return alchemyConfig?.name
18 | ? `https://${alchemyConfig.name}-${alchemyConfig.type}.${MAIN_ALCHEMY_URL}${alchemyApiKey}`
19 | : `http://localhost:8545`
20 | }
21 |
--------------------------------------------------------------------------------
/src/networks/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./chainId"
2 | export * from "./getEthereumNetworkNameFromChainId"
3 | export * from "./connectedNetwork"
4 | export * from "./createExplorerLink"
5 | export * from "./getRpcUrl"
6 | export * from "./mappings"
7 | export * from "./networks"
8 | export * from "./networksAlchemyConfig"
9 | export * from "./getMainnetOrTestnetChainId"
10 |
--------------------------------------------------------------------------------
/src/networks/utils/networksAlchemyConfig.ts:
--------------------------------------------------------------------------------
1 | import { AlchemyName, NetworkType, SupportedChainIds } from "../enums/networks"
2 | import { NetworksAlchemyConfig } from "../types/networks"
3 |
4 | export const networksAlchemyConfig: NetworksAlchemyConfig = {
5 | [SupportedChainIds.Ethereum]: {
6 | name: AlchemyName.Ethereum,
7 | type: NetworkType.Mainnet,
8 | },
9 | [SupportedChainIds.Sepolia]: {
10 | name: AlchemyName.Ethereum,
11 | type: NetworkType.Testnet,
12 | },
13 | [SupportedChainIds.Arbitrum]: {
14 | name: AlchemyName.Arbitrum,
15 | type: NetworkType.Mainnet,
16 | },
17 | [SupportedChainIds.Base]: {
18 | name: AlchemyName.Base,
19 | type: NetworkType.Mainnet,
20 | },
21 | // [SupportedChainIds.BaseSepolia]: {
22 | // name: AlchemyName.Base,
23 | // type: NetworkType.Testnet,
24 | // },
25 | // [SupportedChainIds.ArbitrumSepolia]: {
26 | // name: AlchemyName.Arbitrum,
27 | // type: NetworkType.Testnet,
28 | // },
29 | }
30 |
--------------------------------------------------------------------------------
/src/pages/Feedback/BugReport/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Box } from "@threshold-network/components"
3 | import { PageComponent } from "../../../types"
4 |
5 | const BugReport: PageComponent = () => {
6 | return bug report page
7 | }
8 |
9 | BugReport.route = {
10 | path: "bug-report",
11 | title: "Bug Report",
12 | index: false,
13 | isPageEnabled: true,
14 | }
15 |
16 | export default BugReport
17 |
--------------------------------------------------------------------------------
/src/pages/Feedback/Suggestions/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Box } from "@threshold-network/components"
3 | import { PageComponent } from "../../../types"
4 |
5 | const Suggestions: PageComponent = () => {
6 | return suggestions page
7 | }
8 |
9 | Suggestions.route = {
10 | path: "suggestions",
11 | title: "Suggestions",
12 | index: false,
13 | isPageEnabled: true,
14 | }
15 |
16 | export default Suggestions
17 |
--------------------------------------------------------------------------------
/src/pages/Feedback/UsabilitySurvey/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Box } from "@threshold-network/components"
3 | import { PageComponent } from "../../../types"
4 |
5 | const UsabilitySurvey: PageComponent = () => {
6 | return Usability survey page
7 | }
8 |
9 | UsabilitySurvey.route = {
10 | path: "usability-survey",
11 | title: "Usability Survey",
12 | index: false,
13 | isPageEnabled: true,
14 | }
15 |
16 | export default UsabilitySurvey
17 |
--------------------------------------------------------------------------------
/src/pages/Feedback/index.tsx:
--------------------------------------------------------------------------------
1 | import PageLayout from "../PageLayout"
2 | import { PageComponent } from "../../types"
3 | import UsabilitySurvey from "./UsabilitySurvey"
4 | import Suggestions from "./Suggestions"
5 | import BugReport from "./BugReport"
6 | import Settings from "./Settings"
7 | import { featureFlags } from "../../constants"
8 |
9 | const FeedbackPage: PageComponent = (props) => {
10 | return
11 | }
12 |
13 | FeedbackPage.route = {
14 | path: "feedback",
15 | index: true,
16 | pages: [UsabilitySurvey, Suggestions, BugReport, Settings],
17 | title: "Feedback",
18 | isPageEnabled: featureFlags.FEEDBACK_MODULE,
19 | }
20 |
21 | export default FeedbackPage
22 |
--------------------------------------------------------------------------------
/src/pages/Overview/AnalyticsBanner.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { useColorModeValue } from "@threshold-network/components"
3 | import analyticsImageLight from "../../static/images/AnalyticsIllustration.png"
4 | import analyticsImageDark from "../../static/images/AnalyticsIllustrationDark.png"
5 | import { ModalType } from "../../enums"
6 | import { useModal } from "../../hooks/useModal"
7 | import SecondaryAnnouncementBanner from "../../components/AnnouncementBanner/SecondaryAnnouncementBanner"
8 |
9 | export const AnalyticsBanner: FC = () => {
10 | const { openModal } = useModal()
11 |
12 | const imgSrc = useColorModeValue(analyticsImageLight, analyticsImageDark)
13 |
14 | return (
15 | openModal(ModalType.Analytics)}
21 | />
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/src/pages/Overview/Network/CardTemplate.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { LabelSm, Card, BoxProps } from "@threshold-network/components"
3 |
4 | const CardTemplate: FC<{ title: string | JSX.Element } & BoxProps> = ({
5 | title,
6 | children,
7 | ...boxProps
8 | }) => {
9 | return (
10 |
11 | {typeof title === "string" ? {title} : title}
12 | {children}
13 |
14 | )
15 | }
16 |
17 | export default CardTemplate
18 |
--------------------------------------------------------------------------------
/src/pages/Overview/Network/tBTCBridgeStats.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Card, Divider, LabelSm } from "@threshold-network/components"
3 | import {
4 | ProtocolHistory,
5 | ProtocolHistoryProps,
6 | TBTCText,
7 | Tvl,
8 | TvlProps,
9 | } from "../../../components/tBTC"
10 |
11 | type TBTCBridgeStatsProps = ProtocolHistoryProps & TvlProps
12 |
13 | export const TBTCBridgeStats: FC = ({
14 | tvl,
15 | tvlInUSD,
16 | deposits,
17 | }) => {
18 | return (
19 |
20 |
21 | Bridge Stats
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/src/pages/Staking/HowItWorks/StakingOverview/NewTStakesCard.tsx:
--------------------------------------------------------------------------------
1 | import { FC, ComponentProps } from "react"
2 | import {
3 | BodyMd,
4 | LabelSm,
5 | Card,
6 | FlowStepStatus,
7 | } from "@threshold-network/components"
8 | import StakingChecklist from "../../../../components/StakingTimeline"
9 |
10 | export const NewTStakesCard: FC> = (props) => {
11 | return (
12 |
13 | new threshold stakes
14 |
15 | Before you start staking on Threshold Network, make sure you are aware
16 | of the following requirements:
17 |
18 |
25 |
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/src/pages/Staking/StakeCard/Header/HeaderTitle.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import NotificationPill from "../../../../components/NotificationPill"
3 | import { LabelSm } from "@threshold-network/components"
4 | import { getStakeTitle } from "../../../../utils/getStakeTitle"
5 | import { StakeType } from "../../../../enums"
6 |
7 | export const StakeCardHeaderTitle: FC<{ stakeType?: StakeType }> = ({
8 | stakeType,
9 | }) => {
10 | return (
11 | <>
12 |
13 |
14 | {getStakeTitle(stakeType)}
15 |
16 | >
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/src/pages/Staking/StakeCard/StakeAddressInfo/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { BoxLabel, Flex, FlexProps } from "@threshold-network/components"
3 | import { CopyAddressToClipboard } from "../../../../components/CopyToClipboard"
4 |
5 | const StakeAddressInfo: FC = ({
6 | stakingProvider,
7 | ...restProps
8 | }) => {
9 | return (
10 |
11 |
12 | Provider Address
13 |
14 |
15 |
16 | )
17 | }
18 |
19 | export default StakeAddressInfo
20 |
--------------------------------------------------------------------------------
/src/pages/Staking/StakeCard/StakeBalance/LegacyStakeBalances/BalanceTreeItem.tsx:
--------------------------------------------------------------------------------
1 | import { FC, Fragment, ReactElement } from "react"
2 | import { BodyMd } from "@threshold-network/components"
3 | import { TreeItem, TreeItemLineToNode } from "../../../../../components/Tree"
4 | import InfoBox from "../../../../../components/InfoBox"
5 | import TokenBalance from "../../../../../components/TokenBalance"
6 |
7 | export const BalanceTreeItem: FC<{
8 | label: string | ReactElement
9 | value: string
10 | isRoot?: boolean
11 | }> = ({ label, value, children, isRoot = false }) => {
12 | const LineComponent = isRoot ? Fragment : TreeItemLineToNode
13 | return (
14 |
15 |
16 | {label}
17 |
18 |
19 |
20 |
21 |
22 |
23 | {children}
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/pages/Staking/StakeCard/StakeBalance/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC, useContext } from "react"
2 | import { BodyMd } from "@threshold-network/components"
3 | import InfoBox from "../../../../components/InfoBox"
4 | import TokenBalance from "../../../../components/TokenBalance"
5 | import LegacyStakeBalances from "./LegacyStakeBalances"
6 | import { useStakeCardContext } from "../../../../hooks/useStakeCardContext"
7 |
8 | const StakeBalance: FC<{
9 | nuInTStake: string
10 | keepInTStake: string
11 | tStake: string
12 | totalInTStake: string
13 | }> = ({ nuInTStake, keepInTStake, tStake, totalInTStake }) => {
14 | const { hasLegacyStakes } = useStakeCardContext()
15 |
16 | return hasLegacyStakes ? (
17 |
23 | ) : (
24 | <>
25 |
26 | Total Staked Balance
27 |
28 |
29 |
30 |
31 | >
32 | )
33 | }
34 |
35 | export default StakeBalance
36 |
--------------------------------------------------------------------------------
/src/pages/Staking/StakeDetailsPage/NodeStatusLabel.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from "react"
2 | import { Alert, AlertIcon, BodyXs } from "@threshold-network/components"
3 |
4 | const NodeStatusLabel: FC<{ isAuthorized: boolean }> = ({ isAuthorized }) => {
5 | return (
6 |
7 |
8 | {isAuthorized ? "" : "Not"} Authorized
9 |
10 | )
11 | }
12 |
13 | export default NodeStatusLabel
14 |
--------------------------------------------------------------------------------
/src/pages/Staking/StakeDetailsPage/StakeDetailRow.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { BoxLabel, HStack } from "@threshold-network/components"
3 | import { CopyAddressToClipboard } from "../../../components/CopyToClipboard"
4 |
5 | type CommonProps = {
6 | label: string
7 | isPrimary?: boolean
8 | }
9 | type ConditionalProps =
10 | | {
11 | isAddress?: false
12 | address?: never
13 | }
14 | | {
15 | isAddress: true
16 | address: string
17 | }
18 |
19 | type Props = CommonProps & ConditionalProps
20 |
21 | const StakeDetailRow: FC = ({
22 | label,
23 | isAddress,
24 | address,
25 | isPrimary,
26 | children,
27 | }) => {
28 | return (
29 |
30 | {label}
31 | {isAddress ? (
32 |
36 | ) : (
37 | children
38 | )}
39 |
40 | )
41 | }
42 |
43 | export default StakeDetailRow
44 |
--------------------------------------------------------------------------------
/src/pages/Upgrade/UpgradeKEEP.tsx:
--------------------------------------------------------------------------------
1 | import UpgradeToken from "./UpgradeToken"
2 | import { Token } from "../../enums"
3 | import { PageComponent } from "../../types"
4 | import { useKeep } from "../../web3/hooks"
5 |
6 | const UpgradeKEEP: PageComponent = (props) => {
7 | return
8 | }
9 |
10 | UpgradeKEEP.route = {
11 | path: "keep",
12 | index: false,
13 | title: "KEEP to T",
14 | isPageEnabled: true,
15 | }
16 |
17 | export default UpgradeKEEP
18 |
--------------------------------------------------------------------------------
/src/pages/Upgrade/UpgradeNU.tsx:
--------------------------------------------------------------------------------
1 | import UpgradeToken from "./UpgradeToken"
2 | import { Token } from "../../enums"
3 | import { PageComponent } from "../../types"
4 |
5 | const UpgradeNU: PageComponent = (props) => {
6 | return
7 | }
8 |
9 | UpgradeNU.route = {
10 | path: "nu",
11 | index: true,
12 | title: "NU to T",
13 | isPageEnabled: true,
14 | }
15 |
16 | export default UpgradeNU
17 |
--------------------------------------------------------------------------------
/src/pages/Upgrade/UpgradeToken.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { Stack } from "@threshold-network/components"
3 | import UpgradeCard from "../../components/UpgradeCard"
4 | import TokenBalanceCard from "../../components/TokenBalanceCard"
5 | import { useModal } from "../../hooks/useModal"
6 | import { UpgredableToken, RouteProps } from "../../types"
7 | import { ModalType, Token } from "../../enums"
8 |
9 | const UpgradeToken: FC = ({
10 | token,
11 | }) => {
12 | const { openModal } = useModal()
13 |
14 | const onSubmit = (amount: string | number, token: UpgredableToken) => {
15 | openModal(ModalType.UpgradeToT, {
16 | upgradedAmount: amount,
17 | token,
18 | })
19 | }
20 |
21 | return (
22 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | )
35 | }
36 |
37 | export default UpgradeToken
38 |
--------------------------------------------------------------------------------
/src/pages/Upgrade/index.tsx:
--------------------------------------------------------------------------------
1 | import UpgradeKEEP from "./UpgradeKEEP"
2 | import UpgradeNU from "./UpgradeNU"
3 | import PageLayout from "../PageLayout"
4 | import { PageComponent } from "../../types"
5 |
6 | const UpgradePage: PageComponent = (props) => {
7 | return
8 | }
9 |
10 | UpgradePage.route = {
11 | path: "upgrade",
12 | index: true,
13 | pages: [UpgradeKEEP, UpgradeNU],
14 | title: "Upgrade",
15 | isPageEnabled: true,
16 | }
17 |
18 | export default UpgradePage
19 |
--------------------------------------------------------------------------------
/src/pages/index.ts:
--------------------------------------------------------------------------------
1 | import Overview from "./Overview"
2 | import UpgradePage from "./Upgrade"
3 | import Staking from "./Staking"
4 | import TBTC from "./tBTC"
5 | import Feedback from "./Feedback"
6 |
7 | export const pages = [Overview, TBTC, Staking, UpgradePage, Feedback]
8 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/BridgeActivityCard/index.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentProps, FC } from "react"
2 | import { Card, LabelSm } from "@threshold-network/components"
3 | import {
4 | BridgeAcivityHeader,
5 | BridgeActivity,
6 | BridgeActivityData,
7 | BridgeActivityEmptyHistoryImg,
8 | BridgeActivityProps,
9 | } from "../../../../components/tBTC"
10 |
11 | export const BridgeActivityCard: FC<
12 | ComponentProps & BridgeActivityProps
13 | > = ({ isFetching, data, children, ...props }) => {
14 | return (
15 |
16 | my activity
17 |
18 |
19 |
20 |
21 |
22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/UnmintingCard/index.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentProps, FC } from "react"
2 | import {
3 | Card,
4 | Image,
5 | useColorModeValue,
6 | BodyMd,
7 | } from "@threshold-network/components"
8 | import unmintingEmptyState from "../../../../static/images/unminting-empty-state.svg"
9 | import unmintingEmptyStateDark from "../../../../static/images/unminting-empty-state-dark.svg"
10 |
11 | export const UnmintingCard: FC> = ({
12 | ...props
13 | }) => {
14 | const illustration = useColorModeValue(
15 | unmintingEmptyState,
16 | unmintingEmptyStateDark
17 | )
18 | return (
19 |
20 |
21 |
22 | Unminting feature is not enabled or your network is not supported.
23 |
24 |
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/components/BridgeProcessCardSubTitle.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentProps, FC } from "react"
2 | import { BodyLg, Box, useColorModeValue } from "@threshold-network/components"
3 |
4 | export const BridgeProcessCardSubTitle: FC<
5 | {
6 | stepText: string
7 | subTitle?: string
8 | } & ComponentProps
9 | > = ({ stepText, subTitle, children, ...restProps }) => {
10 | const mainTextColor = useColorModeValue("brand.500", "brand.300")
11 |
12 | return (
13 |
14 |
15 | {stepText}
16 |
17 | {subTitle ? ` - ${subTitle}` : children}
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/components/BridgeProcessDetailsCard.tsx:
--------------------------------------------------------------------------------
1 | import { FC, ComponentProps } from "react"
2 | import { Card } from "@threshold-network/components"
3 | import backroundImage from "../../../../static/images/minting-completed-card-bg.png"
4 |
5 | type BridgeProcessDetailsCardProps = ComponentProps & {
6 | isProcessCompleted: boolean
7 | }
8 |
9 | const processCompletedStyles = {
10 | backgroundImage: backroundImage,
11 | backgroundPosition: "bottom -10px right",
12 | backgroundRepeat: "no-repeat",
13 | }
14 |
15 | export const BridgeProcessDetailsCard: FC = ({
16 | isProcessCompleted,
17 | children,
18 | ...restPros
19 | }) => {
20 | return (
21 |
22 | {children}
23 |
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/components/BridgeProcessDetailsPageSkeleton.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | SkeletonText,
4 | Skeleton,
5 | SkeletonCircle,
6 | } from "@threshold-network/components"
7 |
8 | export const BridgeProcessDetailsPageSkeleton: FC = () => {
9 | return (
10 | <>
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | >
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/components/BridgeProcessResource.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { BodySm, Box, H6, Image } from "@threshold-network/components"
3 | import Link from "../../../../components/Link"
4 | import codeSlashIllustration from "../../../../static/images/code-slash.svg"
5 |
6 | export type BridgeProcessResourceProps = {
7 | title: string
8 | subtitle: string
9 | link: string
10 | }
11 |
12 | export const BridgeProcessResource: FC = ({
13 | title,
14 | subtitle,
15 | link,
16 | }) => {
17 | return (
18 |
19 |
27 |
28 |
29 |
30 | {title}
31 |
32 |
33 | {subtitle}
34 |
35 |
36 |
37 | Read more
38 |
39 |
40 |
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/components/StarkNetLoadingState.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import {
3 | Box,
4 | Spinner,
5 | VStack,
6 | Text,
7 | useColorModeValue,
8 | } from "@threshold-network/components"
9 |
10 | interface StarkNetLoadingStateProps {
11 | message?: string
12 | }
13 |
14 | export const StarkNetLoadingState: React.FC = ({
15 | message = "Initializing Starknet connection...",
16 | }) => {
17 | const bgColor = useColorModeValue("gray.50", "gray.800")
18 | const borderColor = useColorModeValue("gray.200", "gray.700")
19 | const textColor = useColorModeValue("gray.600", "gray.400")
20 |
21 | return (
22 |
30 |
31 |
32 |
33 | {message}
34 |
35 |
36 | This may take a few moments. Please do not close this window.
37 |
38 |
39 |
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/components/TbtcFees.tsx:
--------------------------------------------------------------------------------
1 | import { List } from "@threshold-network/components"
2 | import { TransactionDetailsAmountItem } from "../../../../components/TransactionDetails"
3 |
4 | import { useFetchTBTCFees } from "../../../../hooks/tbtc/useFetchTBTCFees"
5 | import { useIsActive } from "../../../../hooks/useIsActive"
6 | import { SupportedChainIds } from "../../../../networks/enums/networks"
7 |
8 | const TbtcFees = () => {
9 | const {
10 | data: { depositTreasuryFee, optimisticMintingFee, depositTxMaxFee },
11 | isFetching,
12 | } = useFetchTBTCFees()
13 |
14 | return (
15 |
16 |
22 |
28 |
29 | )
30 | }
31 |
32 | export default TbtcFees
33 |
--------------------------------------------------------------------------------
/src/pages/tBTC/Bridge/components/TimelineItem.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import {
3 | Step,
4 | StepBadge,
5 | StepDescription,
6 | StepImage,
7 | StepIndicator,
8 | StepProps,
9 | StepTitle,
10 | } from "../../../../components/Step"
11 |
12 | export type TimelineProps = {
13 | stepText: string
14 | helperLabelText: string
15 | isActive: boolean
16 | isComplete: boolean
17 | title: string | JSX.Element
18 | description: string | JSX.Element
19 | imageSrc?: any
20 | withBadge?: boolean
21 | } & StepProps
22 |
23 | const TimelineItem: FC = ({
24 | stepText,
25 | helperLabelText,
26 | isComplete,
27 | isActive,
28 | title,
29 | description,
30 | imageSrc,
31 | withBadge = true,
32 | ...restProps
33 | }) => {
34 | return (
35 |
36 | {stepText}
37 | {withBadge && {helperLabelText}}
38 | {title}
39 | {description}
40 |
41 |
42 | )
43 | }
44 |
45 | export default TimelineItem
46 |
--------------------------------------------------------------------------------
/src/pages/tBTC/HowItWorks/index.tsx:
--------------------------------------------------------------------------------
1 | import { SimpleGrid, VStack } from "@threshold-network/components"
2 | import { ContractsCard } from "./ContractsCard"
3 | import { AuditsCard } from "./AuditsCard"
4 | import { TbtcBridgeCard } from "./TbtcBridgeCard"
5 | import { MintingTimelineCard } from "./MintingTimelineCard"
6 | import { JSONFileCard } from "./JSONFileCard"
7 | import { Banner } from "./Banner"
8 | import { PageComponent } from "../../../types"
9 |
10 | const HowItWorksPage: PageComponent = (props) => {
11 | return (
12 | <>
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | >
24 | )
25 | }
26 |
27 | HowItWorksPage.route = {
28 | path: "how-it-works",
29 | index: false,
30 | title: "How it Works",
31 | isPageEnabled: true,
32 | }
33 |
34 | export default HowItWorksPage
35 |
--------------------------------------------------------------------------------
/src/pages/tBTC/index.tsx:
--------------------------------------------------------------------------------
1 | import PageLayout from "../PageLayout"
2 | import { PageComponent } from "../../types"
3 | import HowItWorksPage from "./HowItWorks"
4 | import TBTCBridge from "./Bridge"
5 | import { featureFlags } from "../../constants"
6 | import { ExplorerPage } from "./Explorer"
7 | import { ResumeDepositPage } from "./Bridge/ResumeDeposit"
8 |
9 | const MainTBTCPage: PageComponent = (props) => {
10 | const externalLinks = [
11 | {
12 | title: "tBTC Explorer",
13 | href: "https://tbtcscan.com/",
14 | },
15 | ]
16 |
17 | return (
18 |
23 | )
24 | }
25 |
26 | MainTBTCPage.route = {
27 | path: "tBTC",
28 | index: false,
29 | pages: [HowItWorksPage, TBTCBridge, ExplorerPage, ResumeDepositPage],
30 | title: "tBTC",
31 | isPageEnabled: featureFlags.TBTC_V2,
32 | }
33 |
34 | export default MainTBTCPage
35 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | //
2 |
3 | interface Window {
4 | ethereum?: unknown
5 | }
6 |
--------------------------------------------------------------------------------
/src/static/icons/Argent.tsx:
--------------------------------------------------------------------------------
1 | import { useColorModeValue } from "@chakra-ui/react"
2 | import { FC } from "react"
3 |
4 | export const ArgentIcon: FC<{ width?: string; height?: string }> = ({
5 | width = "24",
6 | height = "24",
7 | }) => {
8 | const fillColor = useColorModeValue("#FF875B", "#FF875B")
9 |
10 | return (
11 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/src/static/icons/Base.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | export const Base = createIcon({
4 | displayName: "Base",
5 | viewBox: "0 0 146 146", // Ensure viewBox matches the desired dimensions
6 | path: (
7 | <>
8 |
9 |
13 | >
14 | ),
15 | })
16 |
--------------------------------------------------------------------------------
/src/static/icons/EthereumDark.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | export const EthereumDark = createIcon({
4 | displayName: "EthereumDark",
5 | viewBox: "0 0 24 24",
6 | path: (
7 |
36 | ),
37 | })
38 |
--------------------------------------------------------------------------------
/src/static/icons/EthereumLight.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | export const EthereumLight = createIcon({
4 | displayName: "EthereumLight",
5 | viewBox: "0 0 24 24",
6 | path: (
7 |
33 | ),
34 | })
35 |
--------------------------------------------------------------------------------
/src/static/icons/KeepCircleBrand.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | const KeepCircleBrand = createIcon({
4 | displayName: "KeepCircleBrand",
5 | viewBox: "0 0 32 32",
6 | path: (
7 |
14 | ),
15 | })
16 |
17 | export default KeepCircleBrand
18 |
--------------------------------------------------------------------------------
/src/static/icons/KeepLight.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | const KeepLight = createIcon({
4 | displayName: "KeepLight",
5 | viewBox: "0 0 21 20",
6 | path: (
7 |
19 | ),
20 | })
21 |
22 | export default KeepLight
23 |
--------------------------------------------------------------------------------
/src/static/icons/LedgerDark.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | export const LedgerDark = createIcon({
4 | displayName: "Ledger",
5 | viewBox: "0 0 160 160",
6 | path: (
7 |
20 | ),
21 | })
22 |
--------------------------------------------------------------------------------
/src/static/icons/LedgerLight.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | export const LedgerLight = createIcon({
4 | displayName: "Ledger",
5 | viewBox: "0 0 160 160",
6 | path: (
7 |
20 | ),
21 | })
22 |
--------------------------------------------------------------------------------
/src/static/icons/ThresholdPurple.tsx:
--------------------------------------------------------------------------------
1 | import { createIcon } from "@chakra-ui/icons"
2 |
3 | const ThresholdPurple = createIcon({
4 | displayName: "ThresholdPurple",
5 | viewBox: "0 0 32 32",
6 | path: (
7 |
19 | ),
20 | })
21 |
22 | export default ThresholdPurple
23 |
--------------------------------------------------------------------------------
/src/static/icons/tokenIconMap.ts:
--------------------------------------------------------------------------------
1 | import { ComponentType } from "react"
2 | import KeepCircleBrand from "./KeepCircleBrand"
3 | import NuCircleBrand from "./NuCircleBrand"
4 | import ThresholdCircleBrand from "./ThresholdCircleBrand"
5 |
6 | const tokenIcons = [
7 | "KEEP_CIRCLE_BRAND",
8 | "NU_CIRCLE_BRAND",
9 | "T_CIRCLE_BRAND",
10 | ] as const
11 |
12 | export type TokenIcon = typeof tokenIcons[number]
13 |
14 | const tokenIconMap: Record = {
15 | KEEP_CIRCLE_BRAND: KeepCircleBrand,
16 | NU_CIRCLE_BRAND: NuCircleBrand,
17 | T_CIRCLE_BRAND: ThresholdCircleBrand,
18 | }
19 |
20 | export default tokenIconMap
21 |
--------------------------------------------------------------------------------
/src/static/images/AnalyticsIllustration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/AnalyticsIllustration.png
--------------------------------------------------------------------------------
/src/static/images/AnalyticsIllustrationDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/AnalyticsIllustrationDark.png
--------------------------------------------------------------------------------
/src/static/images/AuthorizingApplicationsIllustrationDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/AuthorizingApplicationsIllustrationDark.png
--------------------------------------------------------------------------------
/src/static/images/AuthorizingApplicationsIllustrationLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/AuthorizingApplicationsIllustrationLight.png
--------------------------------------------------------------------------------
/src/static/images/DiagonalArrowDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/DiagonalArrowDark.png
--------------------------------------------------------------------------------
/src/static/images/DiagonalArrowLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/DiagonalArrowLight.png
--------------------------------------------------------------------------------
/src/static/images/DiagonalPillDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/DiagonalPillDark.png
--------------------------------------------------------------------------------
/src/static/images/DiagonalPillLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/DiagonalPillLight.png
--------------------------------------------------------------------------------
/src/static/images/LearnAboutStakingIllustration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/LearnAboutStakingIllustration.png
--------------------------------------------------------------------------------
/src/static/images/ListIconArrowsDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/ListIconArrowsDark.png
--------------------------------------------------------------------------------
/src/static/images/ListIconArrowsLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/ListIconArrowsLight.png
--------------------------------------------------------------------------------
/src/static/images/ListIconStarDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/ListIconStarDark.png
--------------------------------------------------------------------------------
/src/static/images/ListIconStarLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/ListIconStarLight.png
--------------------------------------------------------------------------------
/src/static/images/ListIconStockDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/ListIconStockDark.png
--------------------------------------------------------------------------------
/src/static/images/ListIconStockLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/ListIconStockLight.png
--------------------------------------------------------------------------------
/src/static/images/MetaMask-Fox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/MetaMask-Fox.png
--------------------------------------------------------------------------------
/src/static/images/RandomBeaconDecrease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/RandomBeaconDecrease.png
--------------------------------------------------------------------------------
/src/static/images/RandomBeaconIncrease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/RandomBeaconIncrease.png
--------------------------------------------------------------------------------
/src/static/images/StakingApplicationsIllustrationDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/StakingApplicationsIllustrationDark.png
--------------------------------------------------------------------------------
/src/static/images/StakingApplicationsIllustrationLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/StakingApplicationsIllustrationLight.png
--------------------------------------------------------------------------------
/src/static/images/StakingHowItWorksIllustrationDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/StakingHowItWorksIllustrationDark.png
--------------------------------------------------------------------------------
/src/static/images/StakingHowItWorksIllustrationLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/StakingHowItWorksIllustrationLight.png
--------------------------------------------------------------------------------
/src/static/images/SunglassesDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/SunglassesDark.png
--------------------------------------------------------------------------------
/src/static/images/SunglassesLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/SunglassesLight.png
--------------------------------------------------------------------------------
/src/static/images/TACoDecrease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/TACoDecrease.png
--------------------------------------------------------------------------------
/src/static/images/TACoIncrease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/TACoIncrease.png
--------------------------------------------------------------------------------
/src/static/images/TbtcDecrease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/TbtcDecrease.png
--------------------------------------------------------------------------------
/src/static/images/TbtcIncrease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/TbtcIncrease.png
--------------------------------------------------------------------------------
/src/static/images/minting-completed-card-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/minting-completed-card-bg.png
--------------------------------------------------------------------------------
/src/static/images/preAppIllustrationDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/preAppIllustrationDark.png
--------------------------------------------------------------------------------
/src/static/images/preAppIllustrationLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/preAppIllustrationLight.png
--------------------------------------------------------------------------------
/src/static/images/randomBeaconAppIllustrationDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/randomBeaconAppIllustrationDark.png
--------------------------------------------------------------------------------
/src/static/images/randomBeaconAppIllustrationLight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/randomBeaconAppIllustrationLight.png
--------------------------------------------------------------------------------
/src/static/images/stakingProviders/BoarLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/stakingProviders/BoarLogo.png
--------------------------------------------------------------------------------
/src/static/images/stakingProviders/ColossusLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/stakingProviders/ColossusLogo.png
--------------------------------------------------------------------------------
/src/static/images/stakingProviders/DelightLogo.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/static/images/stakingProviders/InfStonesLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/stakingProviders/InfStonesLogo.png
--------------------------------------------------------------------------------
/src/static/images/stakingProviders/P2PValidatorLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/stakingProviders/P2PValidatorLogo.png
--------------------------------------------------------------------------------
/src/static/images/stakingProviders/StakedLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/stakingProviders/StakedLogo.png
--------------------------------------------------------------------------------
/src/static/images/tbtc-json-file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/tbtc-json-file.png
--------------------------------------------------------------------------------
/src/static/images/tbtc-success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threshold-network/token-dashboard/05c8be0939a7b868ce3a78f65354d13f71f8f1fc/src/static/images/tbtc-success.png
--------------------------------------------------------------------------------
/src/store/account/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./slice"
2 | export * from "./selectors"
3 |
--------------------------------------------------------------------------------
/src/store/account/selectors.ts:
--------------------------------------------------------------------------------
1 | import { createSelector } from "@reduxjs/toolkit"
2 | import { RootState } from ".."
3 | import { isAddressZero } from "../../web3/utils"
4 | import { AccountState } from "./slice"
5 |
6 | export const selectAccountState = (state: RootState) => state.account
7 |
8 | export const selectMappedOperators = createSelector(
9 | [selectAccountState],
10 | (accountState: AccountState) => {
11 | const { randomBeacon, tbtc, taco } = accountState.operatorMapping.data
12 | const isOperatorMappedOnlyInTbtcForBundledRewards =
13 | !isAddressZero(tbtc) && isAddressZero(randomBeacon)
14 | const isOperatorMappedOnlyInRandomBeaconForBundledRewards =
15 | isAddressZero(tbtc) && !isAddressZero(randomBeacon)
16 |
17 | return {
18 | mappedOperatorTbtc: tbtc,
19 | mappedOperatorRandomBeacon: randomBeacon,
20 | mappedOperatorTaco: taco,
21 | isOperatorMappedOnlyInTbtcForBundledRewards,
22 | isOperatorMappedOnlyInRandomBeaconForBundledRewards,
23 | isOperatorMappedInAllApps:
24 | !isAddressZero(randomBeacon) &&
25 | !isAddressZero(tbtc) &&
26 | !isAddressZero(taco),
27 | }
28 | }
29 | )
30 |
--------------------------------------------------------------------------------
/src/store/eth/ethSlice.ts:
--------------------------------------------------------------------------------
1 | import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
2 | import { exchangeAPI } from "../../utils/exchangeAPI"
3 | import { CoingeckoID } from "../../enums"
4 | import { EthStateData } from "../../types"
5 |
6 | export const fetchETHPriceUSD = createAsyncThunk(
7 | "eth/fetchETHPriceUSD",
8 | async () => {
9 | return await exchangeAPI.fetchCryptoCurrencyPriceUSD(CoingeckoID.ETH)
10 | }
11 | )
12 |
13 | // Store Ethereum data such as balance, balance in usd, gas price and
14 | // other related data to Ethereum chain.
15 | export const ethSlice = createSlice({
16 | name: "eth",
17 | initialState: {
18 | isLoadingPriceUSD: false,
19 | usdPrice: 0,
20 | } as EthStateData,
21 | reducers: {},
22 | extraReducers: (builder) => {
23 | builder.addCase(fetchETHPriceUSD.pending, (state) => {
24 | state.isLoadingPriceUSD = true
25 | })
26 | builder.addCase(fetchETHPriceUSD.fulfilled, (state, action) => {
27 | state.isLoadingPriceUSD = false
28 | state.usdPrice = action.payload
29 | })
30 | },
31 | })
32 |
--------------------------------------------------------------------------------
/src/store/eth/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./ethSlice"
2 |
--------------------------------------------------------------------------------
/src/store/listener.ts:
--------------------------------------------------------------------------------
1 | import {
2 | createListenerMiddleware,
3 | ListenerEffectAPI,
4 | TypedStartListening,
5 | } from "@reduxjs/toolkit"
6 | import { AppDispatch, RootState } from "."
7 | import { Threshold } from "../threshold-ts"
8 | import { threshold } from "../utils/getThresholdLib"
9 |
10 | export const listenerMiddleware = createListenerMiddleware({
11 | extra: { threshold },
12 | })
13 |
14 | export type ExtraArgument = {
15 | threshold: Threshold
16 | }
17 |
18 | export type AppStartListening = TypedStartListening<
19 | RootState,
20 | AppDispatch,
21 | ExtraArgument
22 | >
23 |
24 | export type AppListenerEffectAPI = ListenerEffectAPI<
25 | RootState,
26 | AppDispatch,
27 | ExtraArgument
28 | >
29 |
30 | export const startAppListening =
31 | listenerMiddleware.startListening as AppStartListening
32 |
--------------------------------------------------------------------------------
/src/store/modal/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./modalSlice"
2 |
--------------------------------------------------------------------------------
/src/store/rewards/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./rewardsSlice"
2 | export * from "./selectors"
3 |
--------------------------------------------------------------------------------
/src/store/sidebar/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./sidebarSlice"
2 |
--------------------------------------------------------------------------------
/src/store/sidebar/sidebarSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit"
2 |
3 | export const sidebarSlice = createSlice({
4 | name: "sidebar",
5 | initialState: {
6 | isOpen: false,
7 | },
8 | reducers: {
9 | openSidebar: (state) => {
10 | state.isOpen = true
11 | },
12 | closeSidebar: (state) => {
13 | state.isOpen = false
14 | },
15 | },
16 | })
17 |
18 | export const { openSidebar, closeSidebar } = sidebarSlice.actions
19 |
--------------------------------------------------------------------------------
/src/store/staking-applications/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./slice"
2 | export * from "./effects"
3 | export * from "./selectors"
4 |
--------------------------------------------------------------------------------
/src/store/staking/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./stakingSlice"
2 | export * from "./selectors"
3 |
--------------------------------------------------------------------------------
/src/store/tbtc/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./tbtcSlice"
2 | export * from "./selectors"
3 |
--------------------------------------------------------------------------------
/src/store/tbtc/selectors.ts:
--------------------------------------------------------------------------------
1 | import { createSelector } from "@reduxjs/toolkit"
2 | import { RootState } from ".."
3 |
4 | export const selectBridgeActivity = createSelector(
5 | (state: RootState) => state,
6 | (state) => {
7 | return state.tbtc.bridgeActivity.data
8 | }
9 | )
10 |
--------------------------------------------------------------------------------
/src/store/tokens/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./tokenSlice"
2 |
--------------------------------------------------------------------------------
/src/store/transactions/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./transactionSlice"
2 |
--------------------------------------------------------------------------------
/src/test-helpers/renderWithProviders.tsx:
--------------------------------------------------------------------------------
1 | import { FC, ReactElement } from "react"
2 | import { Provider } from "react-redux"
3 | import { MemoryRouter, MemoryRouterProps } from "react-router-dom"
4 | import { configureStore } from "@reduxjs/toolkit"
5 | import { render, RenderOptions } from "@testing-library/react"
6 | import { rootReducer } from "../store"
7 |
8 | const store = configureStore({
9 | reducer: rootReducer,
10 | })
11 |
12 | const AllTheProviders: FC = ({ children, ...rest }) => {
13 | return (
14 |
15 | {children}
16 |
17 | )
18 | }
19 |
20 | const renderWithProviders = (
21 | ui: ReactElement,
22 | options?: Omit & {
23 | routerProps?: MemoryRouterProps
24 | }
25 | ) =>
26 | render(ui, {
27 | wrapper: (props) => (
28 |
29 | ),
30 | ...options,
31 | })
32 |
33 | export * from "@testing-library/react"
34 | export { renderWithProviders }
35 |
--------------------------------------------------------------------------------
/src/theme/Checkbox.ts:
--------------------------------------------------------------------------------
1 | import { checkboxAnatomy } from "@chakra-ui/anatomy"
2 | import { PartsStyleFunction } from "@chakra-ui/theme-tools"
3 |
4 | const baseStyle: PartsStyleFunction = () => {
5 | return {
6 | control: {
7 | _checked: {
8 | borderColor: "brand.500",
9 | _active: {
10 | borderColor: "brand.500",
11 | },
12 | backgroundColor: "brand.500",
13 | _hover: {
14 | backgroundColor: "brand.500",
15 | borderColor: "brand.500",
16 | },
17 | },
18 | },
19 | icon: {
20 | color: "white",
21 | },
22 | }
23 | }
24 |
25 | export const Checkbox = {
26 | baseStyle,
27 | }
28 |
--------------------------------------------------------------------------------
/src/theme/InfoBox.ts:
--------------------------------------------------------------------------------
1 | import { mode } from "@chakra-ui/theme-tools"
2 |
3 | export const InfoBox = {
4 | defaultProps: {
5 | variant: "base",
6 | },
7 | baseStyle: {
8 | mt: 4,
9 | p: 6,
10 | borderRadius: "md",
11 | mb: 2,
12 | },
13 | variants: {
14 | modal: (props: any) => ({
15 | background: mode("gray.50", "gray.800")(props),
16 | marginTop: 0,
17 | }),
18 | base: (props: any) => ({
19 | background: mode("gray.50", "gray.700")(props),
20 | }),
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/src/theme/Radio.ts:
--------------------------------------------------------------------------------
1 | import { radioAnatomy } from "@chakra-ui/anatomy"
2 | import { PartsStyleFunction } from "@chakra-ui/theme-tools"
3 |
4 | const baseStyle: PartsStyleFunction = () => {
5 | return {
6 | control: {
7 | _checked: {
8 | backgroundColor: "brand.500",
9 | _hover: {
10 | backgroundColor: "brand.500",
11 | },
12 | },
13 | },
14 | label: {
15 | width: "100%",
16 | },
17 | }
18 | }
19 |
20 | export const Radio = {
21 | baseStyle,
22 | }
23 |
--------------------------------------------------------------------------------
/src/theme/Tooltip.ts:
--------------------------------------------------------------------------------
1 | import { theme } from "@chakra-ui/react"
2 | import { SystemStyleFunction, mode, cssVar } from "@chakra-ui/theme-tools"
3 |
4 | const $bg = cssVar("tooltip-bg")
5 | const $arrowBg = cssVar("popper-arrow-bg")
6 |
7 | // TODO: move to the components repo.
8 | const baseStyle: SystemStyleFunction = (props) => {
9 | const bg = mode("white", "gray.300")(props)
10 | const color = mode("gray.700", "gray.900")(props)
11 |
12 | return {
13 | ...theme.components.Tooltip.baseStyle,
14 | fontWeight: 400,
15 | fontSize: "14px",
16 | lineHeight: "20px",
17 | background: bg,
18 | [$bg.variable]: `colors.${bg}`,
19 | bg: [$bg.reference],
20 | [$arrowBg.variable]: [$bg.reference],
21 | color,
22 | p: 2,
23 | borderRadius: "4px",
24 | }
25 | }
26 |
27 | export const Tooltip = {
28 | baseStyle,
29 | }
30 |
--------------------------------------------------------------------------------
/src/theme/fonts.ts:
--------------------------------------------------------------------------------
1 | export const fonts = {
2 | heading: "Inter, sans-serif",
3 | body: "Inter, sans-serif",
4 | }
5 |
--------------------------------------------------------------------------------
/src/threshold-ts/utils/address.ts:
--------------------------------------------------------------------------------
1 | import {
2 | getAddress as ethersGetAddress,
3 | isAddress as ethersIsAddress,
4 | } from "@ethersproject/address"
5 | import { AddressZero } from "@ethersproject/constants"
6 | import { EthereumAddress } from "@keep-network/tbtc-v2.ts"
7 |
8 | export const unprefixedAndUncheckedAddress = (address: string): string => {
9 | const prefix = address.substring(0, 2)
10 | if (prefix === "0x") {
11 | address = address.slice(2)
12 | }
13 | return address.toLowerCase()
14 | }
15 |
16 | export const getAddress = (address: string) => ethersGetAddress(address)
17 |
18 | export const isEthereumAddress = (address: string): boolean =>
19 | ethersIsAddress(address)
20 |
21 | export const isSameETHAddress = (
22 | address1: string,
23 | address2: string
24 | ): boolean => {
25 | return getAddress(address1) === getAddress(address2)
26 | }
27 |
28 | export const isAddressZero = (address: string): boolean =>
29 | isSameETHAddress(address, AddressZero)
30 |
31 | export { AddressZero }
32 |
33 | export const getChainIdentifier = (ethAddress: string): EthereumAddress => {
34 | return EthereumAddress.from(ethAddress)
35 | }
36 |
--------------------------------------------------------------------------------
/src/threshold-ts/utils/chain.ts:
--------------------------------------------------------------------------------
1 | import { BigNumberish } from "ethers"
2 | import { defaultAbiCoder } from "ethers/lib/utils"
3 | import { BITCOIN_PRECISION } from "./bitcoin"
4 | import { to1ePrecision } from "./math"
5 |
6 | export const isValidType = (paramType: string, value: string) => {
7 | try {
8 | defaultAbiCoder.encode([paramType], [value])
9 | return true
10 | } catch (error) {
11 | return false
12 | }
13 | }
14 |
15 | export const fromSatoshiToTokenPrecision = (
16 | value: BigNumberish,
17 | tokenPrecision: number = 18
18 | ) => {
19 | return to1ePrecision(value, tokenPrecision - BITCOIN_PRECISION)
20 | }
21 |
--------------------------------------------------------------------------------
/src/threshold-ts/utils/constants.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber, constants } from "ethers"
2 | import { Stake } from "../staking"
3 |
4 | export const MAX_UINT64 = BigNumber.from("18446744073709551615") // 2^64 - 1
5 | export const ZERO = constants.Zero
6 | export const ADRESS_ZERO = constants.AddressZero
7 | export const RELAYER_BOT_WALLET = "0x45332EEE9b495b1dda896FD53112eaaCC10b2c19"
8 |
9 | export const STANDARD_ERC20_DECIMALS = 18
10 |
11 | export const EMPTY_STAKE: Stake = {
12 | owner: ADRESS_ZERO,
13 | authorizer: ADRESS_ZERO,
14 | beneficiary: ADRESS_ZERO,
15 | stakingProvider: ADRESS_ZERO,
16 | tStake: ZERO,
17 | keepInTStake: ZERO,
18 | nuInTStake: ZERO,
19 | totalInTStake: ZERO,
20 | possibleKeepTopUpInT: ZERO,
21 | possibleNuTopUpInT: ZERO,
22 | }
23 |
--------------------------------------------------------------------------------
/src/threshold-ts/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./address"
2 | export * from "./bitcoin"
3 | export * from "./constants"
4 | export * from "./math"
5 | export * from "./contract"
6 | export * from "./chain"
7 | export * from "./transaction"
8 |
--------------------------------------------------------------------------------
/src/threshold-ts/utils/math.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber, BigNumberish } from "ethers"
2 |
3 | const compare = (
4 | a: BigNumberish,
5 | b: BigNumberish,
6 | nameOfCompareFunction: "lt" | "gt"
7 | ) => {
8 | const _a = BigNumber.from(a)
9 | const _b = BigNumber.from(b)
10 |
11 | return _a[nameOfCompareFunction](_b) ? _a : _b
12 | }
13 |
14 | export const min = (a: BigNumberish, b: BigNumberish) => {
15 | return compare(a, b, "lt")
16 | }
17 |
18 | export const max = (a: BigNumberish, b: BigNumberish) => {
19 | return compare(a, b, "gt")
20 | }
21 |
22 | export function to1ePrecision(n: BigNumberish, precision: number): BigNumber {
23 | const decimalMultiplier = BigNumber.from(10).pow(precision)
24 | return BigNumber.from(n).mul(decimalMultiplier)
25 | }
26 |
27 | export function to1e18(n: BigNumberish): BigNumber {
28 | return to1ePrecision(n, 18)
29 | }
30 |
--------------------------------------------------------------------------------
/src/threshold-ts/utils/transaction.ts:
--------------------------------------------------------------------------------
1 | import { TransactionReceipt } from "@ethersproject/abstract-provider"
2 | import { Hex } from "@keep-network/tbtc-v2.ts"
3 |
4 | export const isReceipt = (arg: unknown): arg is TransactionReceipt =>
5 | !!arg &&
6 | typeof arg === "object" &&
7 | // the two properties below exist on both v5 and v6 receipts :contentReference[oaicite:0]{index=0}
8 | "blockHash" in arg &&
9 | ("transactionHash" in arg || "hash" in arg)
10 |
11 | export const isHexLike = (arg: unknown): arg is Hex =>
12 | !!arg &&
13 | typeof arg === "object" &&
14 | typeof (arg as any).toPrefixedString === "function"
15 |
--------------------------------------------------------------------------------
/src/types/array.ts:
--------------------------------------------------------------------------------
1 | export type ArrayOneOrMore = {
2 | 0: T
3 | } & Array
4 |
--------------------------------------------------------------------------------
/src/types/chain.ts:
--------------------------------------------------------------------------------
1 | export enum ChainType {
2 | EVM = "EVM",
3 | STARKNET = "STARKNET",
4 | SOLANA = "SOLANA",
5 | }
6 |
7 | export interface ChainIdentifier {
8 | type: ChainType
9 | id: string | number
10 | name: string
11 | }
12 |
13 | export interface ChainMetadata {
14 | displayName: string
15 | icon?: string
16 | rpcUrl?: string
17 | explorerUrl?: string
18 | nativeToken?: {
19 | symbol: string
20 | decimals: number
21 | }
22 | }
23 |
24 | export interface ChainValidation {
25 | isValidAddress(address: string): boolean
26 | isValidChainId(chainId: string | number): boolean
27 | normalizeChainId(chainId: string | number): string | number
28 | }
29 |
30 | export interface ChainDepositInfo {
31 | effectiveChainId: number | string
32 | depositAddress: string
33 | extraData?: any
34 | }
35 |
--------------------------------------------------------------------------------
/src/types/eth.ts:
--------------------------------------------------------------------------------
1 | export interface EthStateData {
2 | isLoadingPriceUSD: boolean
3 | usdPrice: number
4 | }
5 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./array"
2 | export * from "./modal"
3 | export * from "./wallet"
4 | export * from "./sidebar"
5 | export * from "./token"
6 | export * from "./eth"
7 | export * from "./page"
8 | export * from "./rewards"
9 | export * from "./staking"
10 | export * from "./staking-applications"
11 | export * from "./tbtc"
12 | export * from "./trm"
13 |
14 | export type FetchingState = {
15 | isInitialFetchDone?: boolean
16 | isFetching: boolean
17 | error: string
18 | data: DataType
19 | }
20 |
21 | export type RangeOperatorType =
22 | | "greater"
23 | | "less"
24 | | "greaterOrEqual"
25 | | "lessOrEqual"
26 |
27 | export type CurrencyType = "BTC" | "ETH" | "tBTC" | "SOL"
28 |
--------------------------------------------------------------------------------
/src/types/page.ts:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { LinkProps } from "@threshold-network/components"
3 |
4 | export type RouteProps = {
5 | path: string
6 | pathOverride?: string
7 | title?: string
8 | index: boolean
9 | pages?: PageComponent[]
10 | hideFromMenu?: boolean
11 | isPageEnabled: boolean
12 | // Paths combined from all Route parents of the current Route
13 | parentPathBase?: string
14 | }
15 |
16 | export type PageComponent = FC & {
17 | route: RouteProps
18 | }
19 |
20 | export type ExternalLinkProps = LinkProps & {
21 | title: string
22 | }
23 |
--------------------------------------------------------------------------------
/src/types/posthog.ts:
--------------------------------------------------------------------------------
1 | export enum PosthogEvent {
2 | ClosedModal = "Closed Modal",
3 | WalletConnected = "Walled Connected",
4 | WalletDisconnected = "Wallet Disconnected",
5 | }
6 |
7 | export enum PosthogButtonId {
8 | GenerateDepositAddress = "generate-deposit-address-button",
9 | InitiateMinting = "initiate-minting-button",
10 | InitiateUnminting = "initiate-unminting-button",
11 | }
12 |
--------------------------------------------------------------------------------
/src/types/rewards.ts:
--------------------------------------------------------------------------------
1 | export interface RewardsJSONData {
2 | totalAmount: string
3 | merkleRoot: string
4 | claims: {
5 | [stakingProvider: string]: {
6 | amount: string
7 | proof: string[]
8 | beneficiary: string
9 | }
10 | }
11 | }
12 |
13 | export interface BonusEligibility {
14 | hasActiveStake: boolean
15 | // No unstaking after the bonus deadline and until mid-July (not even partial
16 | // amounts).
17 | hasUnstakeAfterBonusDeadline: boolean
18 | // Only total staked amount before bonus deadline is taking
19 | // into account.
20 | eligibleStakeAmount: string
21 | reward: string
22 | isRewardClaimed: boolean
23 | isEligible: boolean
24 | }
25 |
26 | export interface InterimRewards {
27 | [stakingProvider: string]: string
28 | }
29 |
30 | export interface StakingBonusRewards {
31 | [stakingProvider: string]: BonusEligibility
32 | }
33 |
--------------------------------------------------------------------------------
/src/types/sidebar.ts:
--------------------------------------------------------------------------------
1 | export interface OpenSidebar {}
2 | export interface CloseSidebar {}
3 |
4 | export type SidebarActionTypes = OpenSidebar | CloseSidebar
5 |
6 | export interface UseSidebar {
7 | (): {
8 | isOpen: boolean
9 | openSidebar: () => SidebarActionTypes
10 | closeSidebar: () => SidebarActionTypes
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/types/staking-applications.ts:
--------------------------------------------------------------------------------
1 | export type AuthorizationStatus =
2 | | "authorization-not-required"
3 | | "to-authorize"
4 | | "authorized"
5 | | "pending-deauthorization"
6 | | "deauthorization-initiation-needed"
7 |
--------------------------------------------------------------------------------
/src/types/state.ts:
--------------------------------------------------------------------------------
1 | export interface UpdateStateActionPayload {
2 | key: StateKey
3 | value: any
4 | }
5 |
--------------------------------------------------------------------------------
/src/types/transaction.ts:
--------------------------------------------------------------------------------
1 | import { Token } from "../enums"
2 | import { TransactionStatus, TransactionType } from "../enums/transactionType"
3 |
4 | export interface UseTransaction {
5 | (): {
6 | setTransactionStatus: (
7 | type: TransactionType,
8 | status: TransactionStatus
9 | ) => TransactionActionTypes
10 | keepApproval: TransactionInfo
11 | nuApproval: TransactionInfo
12 | keepUpgrade: TransactionInfo
13 | nuUpgrade: TransactionInfo
14 | }
15 | }
16 |
17 | export interface TransactionInfo {
18 | token: Token
19 | status: TransactionStatus
20 | }
21 |
22 | export interface SetTransactionStatusPayload {
23 | type: TransactionType
24 | status: TransactionStatus
25 | }
26 |
27 | export interface SetTransactionStatus {
28 | payload: SetTransactionStatusPayload
29 | }
30 |
31 | export type TransactionActionTypes = SetTransactionStatus
32 |
--------------------------------------------------------------------------------
/src/types/trm.ts:
--------------------------------------------------------------------------------
1 | export type TrmState = {
2 | isFetching: boolean
3 | hasFetched: boolean
4 | error: string
5 | }
6 |
7 | export interface TrmPayload {
8 | error: boolean
9 | message: string
10 | data: TrmAccountData
11 | }
12 |
13 | export interface TrmAccountData {
14 | isBlocked: boolean
15 | reason: string
16 | rawData: TrmAccountDetails[]
17 | }
18 |
19 | export interface TrmAccountDetails {
20 | accountExternalId: string | null
21 | address: string
22 | addressRiskIndicators: TrmRiskIndicator[]
23 | addressSubmitted: string
24 | chain: string
25 | entities: TrmEntity[]
26 | trmAppUrl: string
27 | }
28 |
29 | export interface TrmRiskIndicator {
30 | category: string
31 | categoryId: string
32 | categoryRiskScoreLevel: number
33 | categoryRiskScoreLevelLabel: string
34 | incomingVolumeUsd: string
35 | outgoingVolumeUsd: string
36 | riskType: string
37 | totalVolumeUsd: string
38 | }
39 |
40 | export interface TrmEntity {
41 | category: string
42 | categoryId: string
43 | entity: string
44 | riskScoreLevel: number
45 | riskScoreLevelLabel: string
46 | trmAppUrl: string
47 | trmUrn: string
48 | }
49 |
--------------------------------------------------------------------------------
/src/types/wallet.ts:
--------------------------------------------------------------------------------
1 | import { FC } from "react"
2 | import { WalletType } from "../enums"
3 |
4 | export interface WalletOption {
5 | id: WalletType
6 | title: string
7 | icon: {
8 | light: FC
9 | dark: FC
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/crypto.ts:
--------------------------------------------------------------------------------
1 | type HashAlgorithm = "SHA-1" | "SHA-256" | "SHA-384" | "SHA-512"
2 |
3 | export const hashString = async ({
4 | algorithm = "SHA-256",
5 | value,
6 | }: {
7 | algorithm?: HashAlgorithm
8 | value: string
9 | }) =>
10 | Array.prototype.map
11 | .call(
12 | new Uint8Array(
13 | await crypto.subtle.digest(algorithm, new TextEncoder().encode(value))
14 | ),
15 | (x) => ("0" + x.toString(16)).slice(-2)
16 | )
17 | .join("")
18 |
--------------------------------------------------------------------------------
/src/utils/curveAPI.ts:
--------------------------------------------------------------------------------
1 | import axios from "axios"
2 | import { CurveFactoryPoolId, ApiUrl, endpointUrl } from "../enums"
3 |
4 | export type FactoryPool = {
5 | id: CurveFactoryPoolId
6 | address: string
7 | name: string
8 | underlyingCoins: {
9 | symbol: string
10 | }[]
11 | poolUrls: {
12 | swap: string[]
13 | deposit: string[]
14 | withdraw: string[]
15 | }
16 | gaugeCrvApy: number[]
17 | usdTotal: number
18 | }
19 |
20 | const fetchFactoryPool = async (factoryPoolId: CurveFactoryPoolId) => {
21 | const response = await axios.get(
22 | `${ApiUrl.CURVE}${endpointUrl.CURVE_ETHEREUM_POOL}`
23 | )
24 | const factoryPool: FactoryPool | undefined = response.data.data.poolData.find(
25 | (factoryPool: FactoryPool) => factoryPool.id === factoryPoolId
26 | )
27 |
28 | if (!factoryPool) {
29 | throw new Error("Could not fetch the curve pool data.")
30 | }
31 |
32 | return factoryPool
33 | }
34 |
35 | export const curveAPI = {
36 | fetchFactoryPool,
37 | }
38 |
--------------------------------------------------------------------------------
/src/utils/exchangeAPI.ts:
--------------------------------------------------------------------------------
1 | import axios from "axios"
2 | import { CoingeckoID, ApiUrl, endpointUrl } from "../enums"
3 |
4 | const fetchCryptoCurrencyPriceUSD = async (id: CoingeckoID) => {
5 | const response = await axios.get(
6 | `${ApiUrl.COINGECKO}${endpointUrl.COINGECKO_SIMPLE_PRICE}?ids=${id}&${endpointUrl.COINGECKO_VS_CURRENCY}=usd`
7 | )
8 | return response.data[id].usd
9 | }
10 |
11 | export const exchangeAPI = {
12 | fetchCryptoCurrencyPriceUSD,
13 | }
14 |
--------------------------------------------------------------------------------
/src/utils/getContract.ts:
--------------------------------------------------------------------------------
1 | export {
2 | getSigner,
3 | getContract,
4 | getContractAddressFromTruffleArtifact,
5 | } from "../threshold-ts/utils/contract"
6 |
--------------------------------------------------------------------------------
/src/utils/getDefaultBitcoinCredentials.ts:
--------------------------------------------------------------------------------
1 | import { BitcoinClientCredentials } from "../threshold-ts/types"
2 | import { EnvVariable } from "../enums"
3 | import { getEnvVariable } from "./getEnvVariable"
4 |
5 | export const getDefaultBitcoinCredentials = () => {
6 | const credentials: BitcoinClientCredentials[] = [
7 | {
8 | host: getEnvVariable(EnvVariable.ELECTRUM_HOST),
9 | port: +getEnvVariable(EnvVariable.ELECTRUM_PORT),
10 | protocol: getEnvVariable(
11 | EnvVariable.ELECTRUM_PROTOCOL
12 | ) as BitcoinClientCredentials["protocol"],
13 | },
14 | ]
15 |
16 | return credentials
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/getEnvVariable.ts:
--------------------------------------------------------------------------------
1 | import { EnvVariable, EnvVariableKey } from "../enums"
2 | import { SupportedChainIds } from "../networks/enums/networks"
3 |
4 | type EnvMap = { [key in EnvVariableKey]: string }
5 |
6 | const envMap: EnvMap = (
7 | Object.keys(EnvVariable) as Array
8 | ).reduce((reducer, key) => {
9 | reducer[key] = process.env[`REACT_APP_${EnvVariable[key]}`] as string
10 | return reducer
11 | }, {} as EnvMap)
12 |
13 | export const getEnvVariable = (envVar: EnvVariableKey) => {
14 | return envMap[envVar]
15 | }
16 |
17 | export const getEthereumDefaultProviderChainId = () => {
18 | const chainId = getEnvVariable(EnvVariable.DEFAULT_PROVIDER_CHAIN_ID)
19 |
20 | if (!chainId || isNaN(+chainId)) {
21 | return SupportedChainIds.Sepolia
22 | }
23 |
24 | return +chainId
25 | }
26 |
27 | export const shouldUseTestnetDevelopmentContracts =
28 | getEnvVariable(EnvVariable.DAPP_DEVELOPMENT_TESTNET_CONTRACTS) === "true"
29 |
--------------------------------------------------------------------------------
/src/utils/getLedgerLiveAppEthereumSigner.ts:
--------------------------------------------------------------------------------
1 | import { LedgerLiveSigner } from "./ledger"
2 | import { getThresholdLibProvider } from "./getThresholdLib"
3 | import { getEthereumDefaultProviderChainId } from "./getEnvVariable"
4 |
5 | export const getLedgerLiveAppEthereumSigner = (chainId?: number | string) => {
6 | const providerChainId = chainId || getEthereumDefaultProviderChainId()
7 | const provider = getThresholdLibProvider(providerChainId)
8 | return new LedgerLiveSigner(provider)
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/getRangeSign.ts:
--------------------------------------------------------------------------------
1 | import { RangeOperatorType } from "../types"
2 |
3 | type MapType = { [key in RangeOperatorType]: string }
4 |
5 | const signsMap: MapType = {
6 | greater: ">",
7 | less: "<",
8 | greaterOrEqual: "≥",
9 | lessOrEqual: "≤;",
10 | }
11 |
12 | /**
13 | * Returns the range sign for a given range operator.
14 | * @param {RangeOperatorType} operator - The range operator to get the sign for.
15 | * @return {string} The range sign for the given range operator in form of HTML entity.
16 | */
17 | export const getRangeSign = (operator: RangeOperatorType) =>
18 | signsMap[operator] ?? operator
19 |
--------------------------------------------------------------------------------
/src/utils/getStakeTitle.ts:
--------------------------------------------------------------------------------
1 | import { StakeType } from "../enums"
2 |
3 | export const getStakeTitle = (
4 | stakeType?: StakeType,
5 | id?: number | string
6 | ): string => {
7 | const stakeTitleMain = "stake"
8 | const stakeTitleId = id ? ` ${id.toString()}` : ""
9 | const stakeTitleType = !stakeType
10 | ? ""
11 | : stakeType === (StakeType.NU as StakeType) ||
12 | stakeType === (StakeType.KEEP as StakeType)
13 | ? ` - legacy ${StakeType[stakeType]}`
14 | : " - native"
15 | return stakeTitleMain + stakeTitleId + stakeTitleType
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/helpers.ts:
--------------------------------------------------------------------------------
1 | export const delay = (ms: number) => {
2 | return new Promise((resolve) => setTimeout(resolve, ms))
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | // StarkNet-specific helpers
2 | export * from "./tbtcStarknetHelpers"
3 |
4 | // Re-export commonly used utilities
5 | export * from "./tBTC"
6 | export * from "./helpers"
7 | export * from "./formatAmount"
8 | export * from "./shortenAddress"
9 |
--------------------------------------------------------------------------------
/src/utils/isWalletRejectionError.ts:
--------------------------------------------------------------------------------
1 | export const isWalletRejectionError = (error: Error): boolean => {
2 | const { message } = error
3 | if (message === "MetaMask Tx Signature: User denied transaction signature.") {
4 | return true
5 | }
6 | return false
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/setTimeout.ts:
--------------------------------------------------------------------------------
1 | export function setTimeout(callback: VoidFunction, duration: number) {
2 | let requestId: number
3 | let start: number | null = null
4 |
5 | const loop = (timestamp: number) => {
6 | if (!start) {
7 | start = timestamp
8 | }
9 |
10 | if (timestamp - start < duration) {
11 | requestId = requestAnimationFrame(loop)
12 | } else {
13 | callback()
14 | }
15 | }
16 |
17 | requestId = requestAnimationFrame(loop)
18 | return requestId
19 | }
20 |
21 | export function clearTimeout(requestId: number) {
22 | cancelAnimationFrame(requestId)
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils/stakingBonus.ts:
--------------------------------------------------------------------------------
1 | import { FixedNumber } from "@ethersproject/bignumber"
2 | import { stakingBonus as stakingBonusConstants } from "../constants"
3 | import { dateToUnixTimestamp } from "./date"
4 |
5 | export const calculateStakingBonusReward = (eligibleStakeAmount: string) =>
6 | FixedNumber.fromString(eligibleStakeAmount)
7 | .mulUnsafe(
8 | FixedNumber.fromString(stakingBonusConstants.STAKING_BONUS_MULTIPLIER)
9 | )
10 | .toString()
11 | // Remove `.` to return an integer.
12 | .split(".")[0]
13 |
14 | export const isBeforeOrEqualBonusDeadline = (date: Date = new Date()) =>
15 | dateToUnixTimestamp(date) <= stakingBonusConstants.BONUS_DEADLINE_TIMESTAMP
16 |
17 | export const isBetweenBonusDealineAndBonusDistribution = (
18 | date: Date = new Date()
19 | ) => {
20 | const timestamp = dateToUnixTimestamp(date)
21 |
22 | return (
23 | timestamp > stakingBonusConstants.BONUS_DEADLINE_TIMESTAMP &&
24 | timestamp < stakingBonusConstants.REWARDS_DISTRIBUTION_TIMESTAMP
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/utils/trmAPI.ts:
--------------------------------------------------------------------------------
1 | import axios from "axios"
2 | import { TrmPayload } from "../types"
3 | import { ApiUrl, endpointUrl } from "../enums"
4 |
5 | interface WalletScreeningRequest {
6 | address: string
7 | chainId: number
8 | networkName?: string
9 | }
10 |
11 | export async function fetchWalletScreening({
12 | address,
13 | chainId,
14 | networkName,
15 | }: WalletScreeningRequest): Promise {
16 | const requestBody = {
17 | address,
18 | chainId,
19 | networkName,
20 | }
21 |
22 | try {
23 | const response = await axios.post(
24 | `${ApiUrl.TBTC_EXPLORER}${endpointUrl.TRM_WALLET_SCREENING}`,
25 | requestBody
26 | )
27 | return response.data
28 | } catch (error) {
29 | const errorMsg = "Failed to fetch data from TRM Wallet Screening"
30 | console.error(errorMsg, error)
31 | throw new Error(errorMsg)
32 | }
33 | }
34 |
35 | export const trmAPI = {
36 | fetchWalletScreening,
37 | }
38 |
--------------------------------------------------------------------------------
/src/web3/connectors/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./taho"
2 | export * from "./metamask"
3 | export * from "./walletConnect"
4 | export * from "./coinbaseWallet"
5 | export * from "./ledgerLive"
6 | export { AbstractConnector } from "@web3-react/abstract-connector"
7 | export { UserRejectedRequestError } from "@web3-react/injected-connector"
8 |
--------------------------------------------------------------------------------
/src/web3/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./useContract"
2 | export * from "./useERC20"
3 | export * from "./useKeep"
4 | export * from "./useMulticall"
5 | export * from "./useNu"
6 | export * from "./useSendTransaction"
7 | export * from "./useSubscribeToContractEvent"
8 | export * from "./useSubscribeToERC20TransferEvent"
9 | export * from "./useT"
10 | export * from "./useUpgradeToT"
11 | export * from "./useVendingMachineContract"
12 | export * from "./useVendingMachineRatio"
13 | export * from "./useMulticallContract"
14 | export * from "./useKeepBondingContract"
15 | export * from "./useTBTCTokenContract"
16 | export * from "./useTStakingContract"
17 | export * from "./useKeepTokenStakingContract"
18 | export * from "./useClaimMerkleRewardsTransaction"
19 | export * from "./useGetBlock"
20 |
--------------------------------------------------------------------------------
/src/web3/hooks/useApproval.ts:
--------------------------------------------------------------------------------
1 | import { useSendTransaction } from "./useSendTransaction"
2 | import { useTokenAllowance } from "./useTokenAllowance"
3 | import { MaxUint256 } from "@ethersproject/constants"
4 | import { BigNumber } from "ethers"
5 | import { Contract } from "@ethersproject/contracts"
6 |
7 | const useApproval = (
8 | tokenContract?: Contract,
9 | spender?: string,
10 | onSuccess?: () => void | Promise
11 | ) => {
12 | const { sendTransaction, status } = useSendTransaction(
13 | tokenContract!,
14 | "approve",
15 | onSuccess
16 | )
17 |
18 | const allowance = useTokenAllowance(tokenContract, spender)
19 |
20 | const approve = async (amountToApprove = MaxUint256.toString()) => {
21 | if (BigNumber.from(amountToApprove).gte(BigNumber.from(allowance))) {
22 | await sendTransaction(spender, amountToApprove)
23 | }
24 | }
25 |
26 | return { approve, status }
27 | }
28 |
29 | export default useApproval
30 |
--------------------------------------------------------------------------------
/src/web3/hooks/useApproveTStaking.ts:
--------------------------------------------------------------------------------
1 | import { useToken } from "../../hooks/useToken"
2 | import { Token } from "../../enums"
3 | import { useTStakingContract } from "./useTStakingContract"
4 | import useApproval from "./useApproval"
5 |
6 | export const useApproveTStaking = (onSuccess?: () => Promise | void) => {
7 | const tToken = useToken(Token.T)
8 | const tStakingContract = useTStakingContract()
9 | return useApproval(tToken.contract!, tStakingContract?.address, onSuccess)
10 | }
11 |
--------------------------------------------------------------------------------
/src/web3/hooks/useContract.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from "react"
2 | import { useWeb3React } from "@web3-react/core"
3 | import { Contract } from "@ethersproject/contracts"
4 | import { getThresholdLibProvider } from "../../utils/getThresholdLib"
5 | import { getContract } from "../../utils/getContract"
6 |
7 | export function useContract(
8 | address: string,
9 | ABI: any,
10 | withSignerIfPossible = true
11 | ): T | null {
12 | const { library, account, chainId, active } = useWeb3React()
13 |
14 | return useMemo(() => {
15 | if (!address || !ABI) {
16 | return null
17 | }
18 |
19 | return getContract(
20 | address,
21 | ABI,
22 | active ? library : getThresholdLibProvider(),
23 | withSignerIfPossible && account ? account : undefined
24 | )
25 | }, [address, ABI, library, chainId, withSignerIfPossible, account]) as T
26 | }
27 |
--------------------------------------------------------------------------------
/src/web3/hooks/useGetBlock.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { BlockTag } from "@ethersproject/abstract-provider"
3 | import { Web3Provider } from "@ethersproject/providers"
4 | import { useThreshold } from "../../contexts/ThresholdContext"
5 | import { getProviderOrSigner } from "../../threshold-ts/utils"
6 | import { LedgerLiveSigner } from "../../utils/ledger"
7 |
8 | export const useGetBlock = () => {
9 | const threshold = useThreshold()
10 | const ethereumProviderOrSigner =
11 | threshold.config.ethereum.ethereumProviderOrSigner
12 |
13 | return useCallback(
14 | async (blockTag: BlockTag) => {
15 | if (ethereumProviderOrSigner instanceof LedgerLiveSigner) {
16 | return ethereumProviderOrSigner.provider!.getBlock(blockTag)
17 | }
18 | const provider = getProviderOrSigner(
19 | ethereumProviderOrSigner as any
20 | ) as Web3Provider
21 |
22 | return provider.getBlock(blockTag)
23 | },
24 | [ethereumProviderOrSigner]
25 | )
26 | }
27 |
--------------------------------------------------------------------------------
/src/web3/hooks/useKeepBondingContract.ts:
--------------------------------------------------------------------------------
1 | import { AddressZero } from "@ethersproject/constants"
2 | import { SupportedChainIds } from "../../networks/enums/networks"
3 | import { useContract } from "./useContract"
4 | import KeepBonding from "@keep-network/keep-ecdsa/artifacts/KeepBonding.json"
5 | import { useConnectedOrDefaultEthereumChainId } from "../../networks/hooks/useConnectedOrDefaultEthereumChainId"
6 |
7 | const KEEP_BONDING_ADDRESSES = {
8 | // https://etherscan.io/address/0x27321f84704a599aB740281E285cc4463d89A3D5
9 | [SupportedChainIds.Ethereum]: "0x27321f84704a599aB740281E285cc4463d89A3D5",
10 | // TODO: Set local address- how to resolve it in local network?
11 | [SupportedChainIds.Localhost]: AddressZero,
12 | } as Record
13 |
14 | export const useKeepBondingContract = () => {
15 | const defaultOrConnectedChainId = useConnectedOrDefaultEthereumChainId()
16 |
17 | return useContract(
18 | KEEP_BONDING_ADDRESSES[Number(defaultOrConnectedChainId)],
19 | KeepBonding.abi
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/src/web3/hooks/useKeepTokenStakingContract.ts:
--------------------------------------------------------------------------------
1 | import KeepTokenStaking from "@keep-network/keep-core/artifacts/TokenStaking.json"
2 | import { useContract } from "./useContract"
3 | import { SupportedChainIds } from "../../networks/enums/networks"
4 | import { AddressZero } from "@ethersproject/constants"
5 | import { useConnectedOrDefaultEthereumChainId } from "../../networks/hooks/useConnectedOrDefaultEthereumChainId"
6 |
7 | const KEEP_STAKING_ADDRESSES = {
8 | // https://etherscan.io/address/0x1293a54e160D1cd7075487898d65266081A15458
9 | [SupportedChainIds.Ethereum]: "0x1293a54e160D1cd7075487898d65266081A15458",
10 | [SupportedChainIds.Localhost]: AddressZero,
11 | } as Record
12 |
13 | export const useKeepTokenStakingContract = () => {
14 | const defaultOrConnectedChainId = useConnectedOrDefaultEthereumChainId()
15 |
16 | return useContract(
17 | KEEP_STAKING_ADDRESSES[Number(defaultOrConnectedChainId)],
18 | KeepTokenStaking.abi
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/src/web3/hooks/useMulticall.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { useMulticallContract } from "./useMulticallContract"
3 | import { ContractCall } from "../../threshold-ts/multicall"
4 |
5 | export const useMulticall = (calls: ContractCall[]) => {
6 | const multicall = useMulticallContract()
7 |
8 | return useCallback(async () => {
9 | if (!multicall) return []
10 |
11 | try {
12 | const callRequests = calls.map((_) => [
13 | _.address,
14 | _.interface.encodeFunctionData(_.method, _.args),
15 | ])
16 |
17 | const [, result] = await multicall.aggregate(callRequests)
18 |
19 | return result.map((data: string, index: number) => {
20 | const call = calls[index]
21 | return call.interface.decodeFunctionResult(call.method, data)
22 | })
23 | } catch (error) {
24 | console.warn("Multicall failed:", error)
25 | // Return empty results for each call
26 | return calls.map(() => [])
27 | }
28 | }, [JSON.stringify(calls), multicall])
29 | }
30 |
--------------------------------------------------------------------------------
/src/web3/hooks/useMulticallContract.ts:
--------------------------------------------------------------------------------
1 | import { useContract } from "./useContract"
2 | import { MULTICALL_ADDRESSES } from "../../threshold-ts/multicall"
3 | import { useConnectedOrDefaultEthereumChainId } from "../../networks/hooks/useConnectedOrDefaultEthereumChainId"
4 |
5 | const MULTICALL_ABI = [
6 | "function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)",
7 | "function getEthBalance(address addr) view returns (uint256 balance)",
8 | ]
9 |
10 | export const useMulticallContract = () => {
11 | const defaultOrConnectedChainId = useConnectedOrDefaultEthereumChainId()
12 |
13 | return useContract(
14 | MULTICALL_ADDRESSES[Number(defaultOrConnectedChainId)],
15 | MULTICALL_ABI
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/src/web3/hooks/useNuStakingEscrowContract.ts:
--------------------------------------------------------------------------------
1 | import { useThreshold } from "../../contexts/ThresholdContext"
2 |
3 | export const useNuStakingEscrowContract = () => {
4 | const threshold = useThreshold()
5 |
6 | return threshold.staking.legacyNuStakingContract
7 | }
8 |
--------------------------------------------------------------------------------
/src/web3/hooks/useTBTCTokenContract.ts:
--------------------------------------------------------------------------------
1 | import { useErc20TokenContract } from "./useERC20"
2 | import { AddressZero } from "@ethersproject/constants"
3 | import { SupportedChainIds } from "../../networks/enums/networks"
4 | import { useConnectedOrDefaultEthereumChainId } from "../../networks/hooks/useConnectedOrDefaultEthereumChainId"
5 |
6 | export const TBTC_ADDRESSES = {
7 | // https://etherscan.io/address/0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa
8 | [SupportedChainIds.Ethereum]: "0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa",
9 | [SupportedChainIds.Localhost]: AddressZero,
10 | } as Record
11 |
12 | export const useTBTCTokenContract = () => {
13 | const defaultOrConnectedChainId = useConnectedOrDefaultEthereumChainId()
14 | return useErc20TokenContract(
15 | TBTC_ADDRESSES[Number(defaultOrConnectedChainId)]
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/src/web3/hooks/useTStakingAllowance.ts:
--------------------------------------------------------------------------------
1 | import { useToken } from "../../hooks/useToken"
2 | import { Token } from "../../enums"
3 | import { useTStakingContract } from "./useTStakingContract"
4 | import { useTokenAllowance } from "./useTokenAllowance"
5 |
6 | export const useTStakingAllowance = () => {
7 | const { contract: TTokenContract } = useToken(Token.T)
8 | const tStakingContract = useTStakingContract()
9 | return useTokenAllowance(TTokenContract!, tStakingContract?.address)
10 | }
11 |
--------------------------------------------------------------------------------
/src/web3/hooks/useTokenAllowance.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react"
2 | import { useWeb3React } from "@web3-react/core"
3 | import { Contract } from "@ethersproject/contracts"
4 |
5 | export const useTokenAllowance = (
6 | tokenContract?: Contract,
7 | spender?: string
8 | ) => {
9 | const { account } = useWeb3React()
10 | const [allowance, setAllowance] = useState(0)
11 |
12 | useEffect(() => {
13 | const checkAllowance = async () => {
14 | setAllowance(await tokenContract?.allowance(account, spender))
15 | }
16 |
17 | if (tokenContract?.allowance && account && spender) {
18 | checkAllowance()
19 | }
20 | }, [account, tokenContract, spender])
21 |
22 | return allowance
23 | }
24 |
--------------------------------------------------------------------------------
/src/web3/hooks/useUpgradeToT.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from "react"
2 | import { useToken } from "../../hooks/useToken"
3 | import { useSendTransaction } from "./useSendTransaction"
4 | import { useVendingMachineContract } from "./useVendingMachineContract"
5 | import { UpgredableToken } from "../../types"
6 |
7 | export const useUpgradeToT = (from: UpgredableToken) => {
8 | const { contract } = useToken(from)
9 | const vendingMachineContract = useVendingMachineContract(from)
10 | const vendingMachineContractAddress = vendingMachineContract?.address
11 | const { sendTransaction, status } = useSendTransaction(
12 | contract!,
13 | "approveAndCall"
14 | )
15 |
16 | const upgradeToT = useCallback(
17 | async (amount: string) => {
18 | await sendTransaction(vendingMachineContractAddress, amount, [])
19 | },
20 | [sendTransaction, from, vendingMachineContractAddress]
21 | )
22 |
23 | return { upgradeToT, status }
24 | }
25 |
--------------------------------------------------------------------------------
/src/web3/hooks/useVendingMachineContract.ts:
--------------------------------------------------------------------------------
1 | import { UpgredableToken } from "../../types"
2 | import { Token } from "../../enums"
3 | import { useThreshold } from "../../contexts/ThresholdContext"
4 |
5 | export const useVendingMachineContract = (token: UpgredableToken) => {
6 | const threshold = useThreshold()
7 |
8 | if (!threshold.vendingMachines) {
9 | return null
10 | }
11 |
12 | const TOKEN_TO_VENDING_MACHINE_CONTRACT = {
13 | [Token.Keep]: threshold.vendingMachines.keep.contract,
14 | [Token.Nu]: threshold.vendingMachines.nu.contract,
15 | }
16 |
17 | return TOKEN_TO_VENDING_MACHINE_CONTRACT[token]
18 | }
19 |
--------------------------------------------------------------------------------
/src/web3/library.ts:
--------------------------------------------------------------------------------
1 | import { Web3Provider } from "@ethersproject/providers"
2 |
3 | function getLibrary(provider: any) {
4 | return new Web3Provider(provider)
5 | }
6 | export default getLibrary
7 |
--------------------------------------------------------------------------------
/src/web3/utils/connectors.ts:
--------------------------------------------------------------------------------
1 | import { WalletType } from "../../enums"
2 | import {
3 | AbstractConnector,
4 | CoinbaseWalletConnector,
5 | LedgerLiveConnector,
6 | MetaMask,
7 | WalletConnectConnector,
8 | } from "../connectors"
9 |
10 | export const getWalletTypeFromConnector = (
11 | connector: AbstractConnector | undefined
12 | ): WalletType | null => {
13 | if (connector instanceof MetaMask) {
14 | const isMetamask = connector.isMetaMask(window.ethereum)
15 | return isMetamask ? WalletType.Metamask : WalletType.TAHO
16 | }
17 |
18 | if (connector instanceof LedgerLiveConnector) return WalletType.LedgerLive
19 |
20 | if (connector instanceof WalletConnectConnector)
21 | return WalletType.WalletConnect
22 |
23 | if (connector instanceof CoinbaseWalletConnector) return WalletType.Coinbase
24 |
25 | return null
26 | }
27 |
--------------------------------------------------------------------------------
/src/web3/utils/doesErrorInclude.ts:
--------------------------------------------------------------------------------
1 | const doesErrorInclude = (error: any, match: string) => {
2 | return (
3 | error?.data?.message?.includes(match) || error?.message?.includes(match)
4 | )
5 | }
6 |
7 | export default doesErrorInclude
8 |
--------------------------------------------------------------------------------
/src/web3/utils/events.ts:
--------------------------------------------------------------------------------
1 | export { getContractPastEvents } from "../../threshold-ts/utils"
2 |
--------------------------------------------------------------------------------
/src/web3/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./multicall"
2 | export * from "./events"
3 | export * from "./address"
4 | export * from "./files"
5 |
--------------------------------------------------------------------------------
/src/web3/utils/multicall.ts:
--------------------------------------------------------------------------------
1 | import { Contract } from "@ethersproject/contracts"
2 |
3 | export interface ContractCall {
4 | contract: Contract
5 | method: string
6 | args?: any[]
7 | }
8 |
9 | export const getMulticallContractCall = (call: ContractCall) => {
10 | return [
11 | call.contract?.address,
12 | call.contract?.interface.encodeFunctionData(call.method, call.args),
13 | ]
14 | }
15 |
16 | export const decodeMulticallResult = (
17 | result: string[],
18 | calls: ContractCall[]
19 | ) => {
20 | return result.map((data: string, index: number) => {
21 | const call = calls[index]
22 | return call.contract.interface.decodeFunctionResult(call.method, data)
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "esModuleInterop": true,
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "forceConsistentCasingInFileNames": true,
11 | "noFallthroughCasesInSwitch": true,
12 | "module": "esnext",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "types": ["cypress"]
19 | },
20 | "include": ["src"]
21 | }
22 |
--------------------------------------------------------------------------------