├── .eslintrc.json ├── .github └── workflows │ └── issue-to-project.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── apollo ├── client.ts └── generated │ ├── fragmentMetadata.json │ ├── graphql-codegen-generated.ts │ ├── operations.ts │ └── schema.graphql ├── assets ├── icons │ ├── CoingeckoIcon.tsx │ ├── beetx-smarts.svg │ ├── beetx-thinking.svg │ ├── chevron_down3.svg │ ├── discord.svg │ ├── github.svg │ ├── medium.svg │ ├── points.svg │ ├── pool-icon-1.svg │ ├── pool-icon-2.svg │ ├── pool-icon-3.svg │ ├── scales.svg │ └── twitter.svg ├── images │ ├── beets-token-info-OP.png │ ├── beets-token-info.png │ ├── coingecko.svg │ ├── degen-band.png │ ├── fantom-logo.png │ ├── footer-OP.png │ ├── invest-masthead-image-OP.png │ ├── invest-masthead-image.png │ ├── optimism.svg │ ├── pool-owner.png │ ├── powered-by-balancer.svg │ ├── reliquary │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 1x1-transparent.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ ├── 9.png │ │ ├── approve-beets.png │ │ ├── approve-deposit.png │ │ ├── approve-relayer.png │ │ ├── approve-relic.png │ │ ├── approve-vault.png │ │ ├── approve-wftm.png │ │ ├── background.png │ │ ├── complete.png │ │ ├── create-relic.png │ │ ├── finished-relic.png │ │ ├── migrate-legacy.png │ │ ├── migrate-process.png │ │ ├── migrated-minted-fbeets.png │ │ └── unstake-fbeets.png │ ├── rq-1.png │ ├── rq-2.png │ ├── rq-3.png │ ├── sFTMx-header.png │ ├── swap-masthead-image-OP.png │ ├── swap-masthead-image.png │ ├── why-us-OP.png │ └── why-us.png └── logo │ ├── BeetsBalLogo.tsx │ ├── BeetsLogo.tsx │ ├── aura_iso_colors.png │ ├── beets-bal-2.svg │ ├── beets-bal-powered.svg │ ├── beets-bal.svg │ ├── beets-logo.svg │ ├── fmoney-pfp.png │ ├── gyro-white.png │ └── merkl2x.png ├── codegen.yml ├── components ├── accordion │ └── BeetsAccordion.tsx ├── animated-progress │ └── AnimatedProgress.tsx ├── animation │ ├── FadeInBox.tsx │ ├── FadeInOutBox.tsx │ ├── chakra.tsx │ └── chevron │ │ └── AnimatedChevrons.tsx ├── apr-tooltip │ ├── AprText.tsx │ ├── AprTooltip.tsx │ └── StarsIcon.tsx ├── avatar │ └── WalletUserAvatar.tsx ├── badge │ └── PercentChangeBadge.tsx ├── box │ ├── BeetsBox.tsx │ ├── BeetsBoxHeader.tsx │ └── BeetsBoxLineItem.tsx ├── bridge │ ├── BeetsBridgeModal.tsx │ └── useBeetsBalance.tsx ├── button │ ├── BeetsBatchRelayerApprovalButton.tsx │ ├── BeetsMinterApprovalButton.tsx │ ├── BeetsSubmitTransactionButton.tsx │ ├── BeetsTokenApprovalButton.tsx │ ├── BeetsTransactionStepsSubmit.tsx │ └── WalletConnectButton.tsx ├── card │ ├── Card.tsx │ └── CardRow.tsx ├── carousel │ └── BeetsCarousel.tsx ├── charts │ └── TokenPriceLineChart.tsx ├── fallback │ └── FallbackPlaceholder.tsx ├── fonts │ └── BeetsFonts.tsx ├── icons │ ├── IconDiscord.tsx │ ├── IconGithub.tsx │ ├── IconGlobe.tsx │ ├── IconMedium.tsx │ ├── IconTelegram.tsx │ ├── IconTwitter.tsx │ └── IconWallet.tsx ├── info-button │ └── InfoButton.tsx ├── inputs │ ├── BeetsInput.tsx │ ├── BeetsTokenInputWithSlider.tsx │ ├── FtmTokenInput.tsx │ ├── PresetSelector.tsx │ └── TokenInput.tsx ├── link │ └── NextLink.tsx ├── masthead │ └── PageMasthead.tsx ├── modal │ ├── BeetsModal.tsx │ └── ModalSectionHeadline.tsx ├── multi-select │ └── MultiSelect.tsx ├── pool-badge │ ├── PoolBadgeSmall.tsx │ ├── assets │ │ ├── badge-experimental.gif │ │ ├── boosted-by-beefy-exactly.png │ │ ├── built-by-gyroscope.png │ │ ├── gyro-short.svg │ │ ├── overnight-boosted-small.png │ │ ├── reaper-aave-boosted-small.png │ │ ├── reaper-aave-granary-boosted-small.png │ │ ├── reaper-boosted.png │ │ └── reaper-sonne-boosted.png │ └── lib │ │ └── pool-badge-tooltips.ts ├── popup-menu │ └── TextButtonPopupMenu.tsx ├── progress-bar │ └── TopProgressBar.tsx ├── providers │ └── Compose.tsx ├── slippage │ └── SlippageTextLinkMenu.tsx ├── steps │ └── HorizontalSteps.tsx ├── switch-button │ └── SwitchButton.tsx ├── table │ └── PaginatedTable.tsx ├── tabs │ └── BeetsTab.tsx ├── toast │ ├── BeetsToast.tsx │ ├── TransactionStatusToast.tsx │ └── toast-util.ts ├── token-select-inline │ └── TokenSelectInline.tsx ├── token-select │ ├── GenericTokenSelectModal.tsx │ ├── TokenActionRow.tsx │ ├── TokenImportAlertDialog.tsx │ ├── TokenRow.tsx │ ├── TokenSelectSearchInput.tsx │ └── TokenSelectTokenList.tsx ├── token │ ├── PoolTokenPill.tsx │ ├── TokenAmountPill.tsx │ ├── TokenAvatar.tsx │ ├── TokenAvatarSet.tsx │ ├── TokenAvatarSetInList.tsx │ └── TokenRow.tsx ├── tooltip │ ├── BeetsTooltip.tsx │ └── CustomTooltip.tsx ├── transaction │ ├── SubTransactionSubmittedContent.tsx │ └── TransactionSubmittedContent.tsx ├── typography │ ├── BeetsHeadline.tsx │ └── BeetsSubHeadline.tsx └── user-warning │ └── UserWarning.tsx ├── declarations.d.ts ├── lib ├── abi │ ├── AaveWrapping.json │ ├── BalancerPoolToken.json │ ├── BalancerPseudoMinter.json │ ├── BalancerQueries.json │ ├── BalancerRelayer.json │ ├── BalancerSorQueries.json │ ├── BasePoolFactory.json │ ├── BatchRelayer.json │ ├── BatchRelayerLibrary.json │ ├── BatchRelayerView.json │ ├── BeethovenCheckpointer.json │ ├── BeethovenxMasterChef.json │ ├── BeethovenxNft.json │ ├── BeetsOftProxyV2.json │ ├── BooMirrorWorldStaking.json │ ├── ChildChainGaugeRewardHelper.json │ ├── ConvergentCurvePool.json │ ├── DelegateRegistry.json │ ├── ERC20.json │ ├── Erc4626Wrapping.json │ ├── ExchangeProxy.json │ ├── FBeetsBarStaking.json │ ├── FTMStaking.json │ ├── FreshBeets.json │ ├── GaugeActions.json │ ├── GaugeWorkingBalanceHelper.json │ ├── LinearPool.json │ ├── LinearPoolRebalancer.json │ ├── LiquidityGaugeV5.json │ ├── LiquidityGaugeV6.json │ ├── MasterChefStaking.json │ ├── MultiBeetsMigration.json │ ├── ReaperManualRebalancer.json │ ├── ReaperWrapping.json │ ├── Reliquary.json │ ├── ReliquaryStaking.json │ ├── StablePhantomPool.json │ ├── StablePool.json │ ├── StaticATokenRateProvider.json │ ├── TarotWrapping.json │ ├── TimeBasedRewarder.json │ ├── Vault.json │ ├── VaultAbi.json │ ├── VaultActions.json │ ├── WETH.json │ ├── WeightedPool.json │ ├── WeightedPool2Tokens.json │ ├── WeightedPool2TokensFactory.json │ ├── WeightedPoolFactory.json │ ├── WeightedPoolFactoryV4.json │ └── YearnWrapping.json ├── config │ ├── fantom.ts │ ├── network-config-type.ts │ ├── network-config.ts │ └── optimism.ts ├── global │ ├── batchJsonRpcProvider.ts │ ├── constants.ts │ ├── graphql │ │ └── global.gql │ ├── network.ts │ ├── useEarlyLudwigNft.ts │ ├── useGlobalWarnings.tsx │ ├── useMasterChefHarvestAllRewards.ts │ ├── useNetworkConfig.ts │ ├── useOldBeetsBalance.ts │ ├── useSlippage.ts │ ├── useStakingBoosts.ts │ ├── useStakingClaimRewards.ts │ ├── useStakingDeposit.ts │ ├── useStakingMintableRewards.ts │ ├── useStakingPendingRewards.ts │ ├── useStakingTotalStakedBalance.ts │ ├── useStakingWithdraw.ts │ ├── useSubgraphQuery.ts │ └── useToken.tsx ├── services │ ├── batch-relayer │ │ ├── batch-relayer.service.ts │ │ ├── extensions │ │ │ ├── aave-wrapping.service.ts │ │ │ ├── boo-mirror-world-staking.service.ts │ │ │ ├── erc4626-wrapping.service.ts │ │ │ ├── fbeets-bar-staking.service.ts │ │ │ ├── gauge-actions.service.ts │ │ │ ├── masterchef-staking.service.ts │ │ │ ├── reaper-wrapping.service.ts │ │ │ ├── reliquary-staking.service.ts │ │ │ ├── tarot-supply-vault.service.ts │ │ │ ├── vault-actions.service.ts │ │ │ └── yearn-wrapping.service.ts │ │ └── relayer-types.ts │ ├── nft │ │ └── nft.service.ts │ ├── pool │ │ ├── lib │ │ │ ├── big-int-basic-operations.ts │ │ │ ├── old-big-number.ts │ │ │ ├── pool-base.service.ts │ │ │ ├── pool-composable-exit.service.ts │ │ │ ├── pool-composable-join.service.ts │ │ │ ├── pool-proportional-invest.service.ts │ │ │ ├── stable-math.ts │ │ │ └── util.ts │ │ ├── pool-composable-stable.service.ts │ │ ├── pool-gyro.service.ts │ │ ├── pool-meta-stable.service.ts │ │ ├── pool-on-chain-balance.service.ts │ │ ├── pool-phantom-stable-util.ts │ │ ├── pool-phantom-stable.service.ts │ │ ├── pool-stable.service.ts │ │ ├── pool-types.ts │ │ ├── pool-util.ts │ │ ├── pool-weighted-boosted.service.ts │ │ ├── pool-weighted-compose.service.ts │ │ ├── pool-weighted-v2.service.ts │ │ ├── pool-weighted.service.ts │ │ └── sor-query.service.ts │ ├── rpc-provider │ │ └── static-json-rpc-batch-provier.ts │ ├── staking │ │ ├── fresh-beets.service.ts │ │ ├── gauge-staking.service.ts │ │ ├── gauge.service.ts │ │ ├── master-chef.service.ts │ │ ├── reliquary-zap.service.ts │ │ ├── reliquary.service.ts │ │ ├── sftmx.service.ts │ │ └── staking-types.ts │ ├── token │ │ ├── concerns │ │ │ ├── allowances.concern.ts │ │ │ ├── balances.concern.ts │ │ │ └── metadata.concern.ts │ │ ├── token-types.ts │ │ ├── token-util.ts │ │ └── token.service.ts │ └── util │ │ ├── gas-price.service.ts │ │ ├── multicaller.service.ts │ │ └── snapshot.service.ts ├── user │ ├── graphql │ │ └── user.gql │ ├── useUserAccount.ts │ ├── useUserBalances.tsx │ ├── useUserData.tsx │ ├── useUserImportedTokens.ts │ ├── useUserPendingRewards.ts │ └── useUserTokenBalances.tsx ├── util │ ├── address.ts │ ├── apr-util.ts │ ├── custom-hooks.ts │ ├── ethers-v6.ts │ ├── etherscan.ts │ ├── input-util.ts │ ├── number-formats.ts │ ├── random.ts │ ├── transaction-util.ts │ ├── urls.ts │ ├── useAllowances.ts │ ├── useApproveBatchRelayer.ts │ ├── useApproveMinter.ts │ ├── useApproveToken.ts │ ├── useBalances.ts │ ├── useHasBatchRelayerApproval.ts │ ├── useHasMinterApproval.ts │ ├── useMultiCall.ts │ ├── useSubmitTransaction.tsx │ ├── useUnwrapEth.ts │ ├── useUserAllowances.ts │ ├── useWrapEth.ts │ └── web3.ts └── wallet │ └── useWalletConnectMetadata.tsx ├── modules ├── compose │ ├── AdvancedPoolComposeFeeManager.tsx │ ├── AdvancedPoolComposeFees.tsx │ ├── AdvancedPoolComposeName.tsx │ ├── AdvancedPoolComposeProgress.tsx │ ├── AdvancedPoolComposeSubmit.tsx │ ├── AdvancedPoolComposeTokens.tsx │ ├── AdvancedPoolCreation.tsx │ ├── ComposeChooseFlowType.tsx │ ├── ComposeFlow.tsx │ ├── ComposeProvider.tsx │ ├── FinalisePoolComposeActions.tsx │ ├── PoolComposePreview.tsx │ ├── PreviewPoolTokenFees.tsx │ ├── PreviewPoolTokenSelections.tsx │ ├── SimpleCreationChooseTokens.tsx.tsx │ └── lib │ │ ├── useGetComposePoolId.ts │ │ └── usePoolCreate.ts ├── global │ └── GlobalRenderer.tsx ├── migrate │ ├── BeetsMigration.tsx │ ├── BeetsMigrationButton.tsx │ └── lib │ │ └── useMigrateBeets.ts ├── nav │ ├── Footer.tsx │ ├── FooterLink.tsx │ ├── Navbar.tsx │ ├── NavbarAdditionalLinksMenu.tsx │ ├── NavbarLink.tsx │ ├── NavbarMobile.tsx │ ├── NavbarPendingRewards.tsx │ ├── NavbarPendingRewardsReliquary.tsx │ ├── NavbarWalletConnectButton.tsx │ ├── NetworkSelectorPopover.tsx │ ├── SubNavBar.tsx │ ├── SubNavBarStat.tsx │ └── lib │ │ ├── useGaugeClaimGetContractCallData.ts │ │ ├── useUserGaugeClaimAllPendingRewards.ts │ │ └── useUserHarvestAllPendingRewards.ts ├── pool │ ├── detail │ │ ├── Pool.tsx │ │ └── components │ │ │ ├── PoolDetailActions.tsx │ │ │ ├── PoolDetailCharts.tsx │ │ │ ├── PoolDetailMyBalance.tsx │ │ │ ├── PoolDetailPossibleYieldText.tsx │ │ │ ├── PoolHeader.tsx │ │ │ ├── PoolHeaderStaking.tsx │ │ │ ├── PoolHeaderStats.tsx │ │ │ ├── charts │ │ │ ├── PoolDetailBptPriceChart.tsx │ │ │ ├── PoolDetailFeesChart.tsx │ │ │ ├── PoolDetailVolumeLiquidityChart.tsx │ │ │ └── chart-util.ts │ │ │ ├── composition │ │ │ ├── PoolComposition.tsx │ │ │ ├── PoolCompositionRow.tsx │ │ │ └── PoolCompositionToken.tsx │ │ │ ├── stats │ │ │ ├── PoolOverallStats.tsx │ │ │ ├── PoolStats.tsx │ │ │ ├── PoolUserStakedStats.tsx │ │ │ └── PoolUserStats.tsx │ │ │ ├── thirdparty │ │ │ ├── PoolHeaderPoints.tsx │ │ │ ├── PoolHeaderStakingAura.tsx │ │ │ ├── PoolHeaderStakingFmoney.tsx │ │ │ ├── PoolHeaderStakingMerkl.tsx │ │ │ └── PoolStatsGyroscope.tsx │ │ │ └── warning │ │ │ ├── PoolDetailWarning.tsx │ │ │ ├── PoolMigrateLegacyFbeetsWarning.tsx │ │ │ ├── PoolOvernightWarning.tsx │ │ │ ├── PoolStakeInFarmWarning.tsx │ │ │ └── PoolWarnings.tsx │ ├── invest │ │ ├── PoolInvestModal.tsx │ │ ├── components │ │ │ ├── PoolInvestActions.tsx │ │ │ ├── PoolInvestCustom.tsx │ │ │ ├── PoolInvestPreview.tsx │ │ │ ├── PoolInvestPriceImpact.tsx │ │ │ ├── PoolInvestProportional.tsx │ │ │ ├── PoolInvestSettings.tsx │ │ │ ├── PoolInvestStablePoolDescription.tsx │ │ │ ├── PoolInvestSummary.tsx │ │ │ ├── PoolInvestTypeChoice.tsx │ │ │ └── PoolInvestWeightedPoolDescription.tsx │ │ └── lib │ │ │ ├── useInitJoinPool.ts │ │ │ ├── useInvest.ts │ │ │ ├── useInvestState.ts │ │ │ ├── useJoinPool.ts │ │ │ ├── usePoolGetMaxProportionalInvestmentAmount.ts │ │ │ ├── usePoolInitJoinContractCallData.ts │ │ │ ├── usePoolJoinGetBptOutAndPriceImpactForTokensIn.ts │ │ │ ├── usePoolJoinGetContractCallData.ts │ │ │ └── usePoolJoinGetProportionalInvestmentAmount.ts │ ├── lib │ │ ├── usePool.tsx │ │ ├── usePoolComposableUserPoolTokenBalances.tsx │ │ ├── usePoolGaugeClaimRewardsGetContractCallData.ts │ │ ├── usePoolUserBptBalance.tsx │ │ ├── usePoolUserDepositBalance.tsx │ │ ├── usePoolUserInvestedTokenBalances.tsx │ │ ├── usePoolUserPendingRewards.tsx │ │ ├── usePoolUserTokenBalancesInWallet.tsx │ │ └── usePoolWithOnChainData.tsx │ ├── pool.gql │ ├── stake │ │ ├── PoolMigrateGaugeModal.tsx │ │ ├── PoolStakeModal.tsx │ │ ├── PoolUnstakeModal.tsx │ │ └── lib │ │ │ ├── useCheckpointTrigger.ts │ │ │ ├── useGaugeCheckpoint.ts │ │ │ ├── useGaugeStakingMigration.ts │ │ │ ├── useGaugeUnstakeGetContractCallData.ts │ │ │ ├── usePoolUserStakingAllowance.ts │ │ │ └── useVeMigrationTrigger.ts │ └── withdraw │ │ ├── PoolWithdrawModal.tsx │ │ ├── components │ │ ├── PoolWithdrawPreview.tsx │ │ ├── PoolWithdrawProportional.tsx │ │ ├── PoolWithdrawSettings.tsx │ │ ├── PoolWithdrawSingleAsset.tsx │ │ ├── PoolWithdrawStablePoolDescription.tsx │ │ ├── PoolWithdrawSummary.tsx │ │ ├── PoolWithdrawTypeChoice.tsx │ │ └── PoolWithdrawWeightedPoolDescription.tsx │ │ └── lib │ │ ├── useExitPool.ts │ │ ├── usePoolExitGetBptInForSingleAssetWithdraw.ts │ │ ├── usePoolExitGetContractCallData.ts │ │ ├── usePoolExitGetProportionalWithdrawEstimate.ts │ │ ├── usePoolExitGetSingleAssetWithdrawForBptIn.ts │ │ ├── useWithdraw.ts │ │ └── useWithdrawState.ts ├── pools │ ├── PoolList.tsx │ ├── components │ │ ├── PoolListAttributeMultiSelect.tsx │ │ ├── PoolListItem.tsx │ │ ├── PoolListItemStaking.tsx │ │ ├── PoolListItemWarning.tsx │ │ ├── PoolListMobileHeader.tsx │ │ ├── PoolListSearch.tsx │ │ ├── PoolListSortLink.tsx │ │ ├── PoolListTableHeader.tsx │ │ ├── PoolListTabs.tsx │ │ ├── PoolListTokenMultiSelect.tsx │ │ ├── PoolListTop.tsx │ │ └── thirdparty │ │ │ ├── PoolListItemPoints.tsx │ │ │ ├── PoolListItemStakingAura.tsx │ │ │ ├── PoolListItemStakingFmoney.tsx │ │ │ └── PoolListItemStakingMerkl.tsx │ ├── pools.gql │ └── usePoolList.tsx ├── recovery-exit │ ├── RecoveryExitContent.tsx │ ├── components │ │ ├── RecoveryExitWithdrawListItem.tsx │ │ └── RecoveryExitWithdrawTableHeader.tsx │ └── lib │ │ ├── useDoRecoveryExit.ts │ │ └── useGetRecoveryPoolTokens.ts ├── reliquary │ ├── ReliquaryLanding.tsx │ ├── components │ │ ├── DelegateClearButton.tsx │ │ ├── DelegateSetButton.tsx │ │ ├── RelicBurnButton.tsx │ │ ├── RelicCarousel.tsx │ │ ├── RelicLevelUpButton.tsx │ │ ├── RelicMaturityModal.tsx │ │ ├── RelicSlide.tsx │ │ ├── RelicSlideApr.tsx │ │ ├── RelicSlideInfo.tsx │ │ ├── RelicSlideMainInfo.tsx │ │ ├── ReliquaryBatchRelayerApprovalButton.tsx │ │ ├── ReliquaryConnectWallet.tsx │ │ ├── ReliquaryMigrateModal.tsx │ │ ├── ReliquaryTokensBreakdown.tsx │ │ ├── ReliquaryTransactionStepsSubmit.tsx │ │ ├── charts │ │ │ ├── RelicMaturity.tsx │ │ │ ├── RelicMaturityBarChart.tsx │ │ │ ├── ReliquaryCurveChart.tsx │ │ │ ├── ReliquaryDetailsCharts.tsx │ │ │ ├── ReliquaryLiquidityChart.tsx │ │ │ ├── ReliquaryMaBEETSLevelChart.tsx │ │ │ ├── ReliquaryMaturityChart.tsx │ │ │ └── ReliquaryRelicsCountChart.tsx │ │ ├── stats │ │ │ ├── ReliquaryGlobalStats.tsx │ │ │ └── ReliquaryOverallStats.tsx │ │ └── unused │ │ │ ├── Relic.tsx │ │ │ ├── RelicAchievements.tsx │ │ │ ├── RelicApr.tsx │ │ │ ├── RelicHeader.tsx │ │ │ ├── RelicLiquidity.tsx │ │ │ ├── RelicNFT.tsx │ │ │ ├── RelicRewards.tsx │ │ │ ├── RelicStats.tsx │ │ │ ├── Reliquary.tsx │ │ │ ├── ReliquaryCard.tsx │ │ │ ├── ReliquaryInvest.tsx │ │ │ ├── ReliquaryMigrateDemoButton.tsx │ │ │ ├── ReliquaryMyStats.tsx │ │ │ └── ReliquaryWithdrawDemoButton.tsx │ ├── detail │ │ └── ReliquaryPool.tsx │ ├── invest │ │ ├── ReliquaryInvestModal.tsx │ │ ├── components │ │ │ ├── ReliquaryInvestActions.tsx │ │ │ ├── ReliquaryInvestCustom.tsx │ │ │ ├── ReliquaryInvestDepositImpact.tsx │ │ │ ├── ReliquaryInvestImage.tsx │ │ │ ├── ReliquaryInvestPreview.tsx │ │ │ ├── ReliquaryInvestProportional.tsx │ │ │ ├── ReliquaryInvestSettings.tsx │ │ │ ├── ReliquaryInvestSummary.tsx │ │ │ ├── ReliquaryInvestTitle.tsx │ │ │ └── ReliquaryInvestTypeChoice.tsx │ │ └── lib │ │ │ ├── useReliquaryInvest.ts │ │ │ ├── useReliquaryInvestState.ts │ │ │ ├── useReliquaryJoinGetBptOutAndPriceImpactForTokensIn.ts │ │ │ └── useReliquaryJoinGetProportionalInvestmentAmount.ts │ ├── lib │ │ ├── reliquary-helpers.ts │ │ ├── useAllRelicsDepositBalances.tsx │ │ ├── useAllRelicsWithdrawAndHarvestContractCallData.tsx │ │ ├── useBatchRelayerHasApprovedForAll.ts │ │ ├── useBatchRelayerHasRelicApproval.ts │ │ ├── useBatchRelayerRelicApprove.ts │ │ ├── useBridgeBeets.ts │ │ ├── useDelegateClear.tsx │ │ ├── useDelegateSet.tsx │ │ ├── useDelegation.tsx │ │ ├── useLegacyFbeetsBalance.ts │ │ ├── useRelicBurn.tsx │ │ ├── useRelicDepositBalance.tsx │ │ ├── useRelicHarvestRewards.ts │ │ ├── useRelicPendingRewards.ts │ │ ├── useReliquary.ts │ │ ├── useReliquaryCurrentStep.tsx │ │ ├── useReliquaryDepositContractCallData.ts │ │ ├── useReliquaryDepositImpact.ts │ │ ├── useReliquaryFbeetsMigrateContractCallData.ts │ │ ├── useReliquaryGlobalStats.ts │ │ ├── useReliquaryHarvestAllContractCallData.ts │ │ ├── useReliquaryHarvestAllRewards.ts │ │ ├── useReliquaryLevelUp.ts │ │ ├── useReliquaryPendingRewards.ts │ │ ├── useReliquaryWithdrawAndHarvestContractCallData.ts │ │ └── useReliquaryZap.ts │ ├── migrate │ │ ├── ReliquarySonicMigrateModal.tsx │ │ └── components │ │ │ ├── ReliquarySonicMigrateBridgeBeets.tsx │ │ │ ├── ReliquarySonicMigrateBridgeFtm.tsx │ │ │ ├── ReliquarySonicMigrateExitRelics.tsx │ │ │ ├── ReliquarySonicMigrateNextSteps.tsx │ │ │ ├── ReliquarySonicMigrateStakeS.tsx │ │ │ └── ReliquarySonicMigrateUnwrapFtm.tsx │ ├── reliquary.gql │ └── withdraw │ │ ├── ReliquaryWithdrawModal.tsx │ │ ├── components │ │ ├── ReliquaryWithdrawDescription.tsx │ │ ├── ReliquaryWithdrawPreview.tsx │ │ ├── ReliquaryWithdrawProportional.tsx │ │ ├── ReliquaryWithdrawSettings.tsx │ │ ├── ReliquaryWithdrawSingleAsset.tsx │ │ ├── ReliquaryWithdrawSummary.tsx │ │ └── ReliquaryWithdrawTypeChoice.tsx │ │ └── lib │ │ ├── useReliquaryExitGetBptInForSingleAssetWithdraw.ts │ │ ├── useReliquaryExitGetProportionalWithdrawEstimate.ts │ │ ├── useReliquaryExitGetSingleAssetWithdrawForBptIn.ts │ │ ├── useReliquaryWithdraw.ts │ │ └── useReliquaryWithdrawState.ts └── sftmx │ ├── SftmxLanding.tsx │ ├── components │ ├── charts │ │ ├── SftmxChartsFtmStakedFree.tsx │ │ └── SftmxChartsFtmValidator.tsx │ ├── stats │ │ ├── SftmxOverallStats.tsx │ │ ├── SftmxStatsFtmStakedFree.tsx │ │ ├── SftmxStatsFtmValidator.tsx │ │ └── SftmxStatsVaults.tsx │ ├── table │ │ ├── SftmxTableVaults.tsx │ │ ├── SftmxTableVaultsHeader.tsx │ │ └── SftmxTableVaultsRow.tsx │ └── tabs │ │ ├── stake │ │ ├── SftmxStakeButton.tsx │ │ └── SftmxStakeTab.tsx │ │ ├── unstake │ │ ├── SftmxUnstakeButton.tsx │ │ └── SftmxUnstakeTab.tsx │ │ └── withdraw │ │ ├── SftmxWithdrawButton.tsx │ │ ├── SftmxWithdrawTab.tsx │ │ ├── SftmxWithdrawalRequestsHeader.tsx │ │ └── SftmxWithdrawalRequestsRow.tsx │ ├── lib │ ├── useSftmxGetAllWithdrawalRequests.ts │ ├── useSftmxGetCalculatePenalty.ts │ ├── useSftmxGetFtmxAmountForFtm.ts │ ├── useSftmxGetStakingData.ts │ ├── useSftmxGetWithdrawalRequests.ts │ ├── useSftmxStake.ts │ ├── useSftmxUnstake.ts │ └── useSftmxWithdraw.ts │ └── sftmx.gql ├── next-env.d.ts ├── next.config.js ├── package.json ├── pages ├── 404.tsx ├── _app-content.tsx ├── _app.tsx ├── _document.tsx ├── _error.tsx ├── api │ ├── revalidate.ts │ └── rpc │ │ └── [chain] │ │ └── routes.ts ├── compose.tsx ├── index.tsx ├── mabeets.tsx ├── pool │ └── [poolId] │ │ └── index.tsx ├── pools.tsx ├── recovery-exit.tsx ├── sftmx.tsx ├── swap.tsx └── terms-of-service.tsx ├── patches └── @ethersproject+providers+5.6.6.patch ├── public ├── favicon.ico ├── fonts │ ├── gotham-bold-webfont.woff │ ├── gotham-bold-webfont.woff2 │ ├── gotham-book-webfont.woff │ ├── gotham-book-webfont.woff2 │ ├── gotham-light-webfont.woff │ ├── gotham-light-webfont.woff2 │ ├── gotham-medium-webfont.woff │ └── gotham-medium-webfont.woff2 ├── images │ ├── hero-image-fantom-mobile.jpg │ ├── hero-image-fantom.jpg │ ├── hero-image-optimism-mobile.jpg │ └── hero-image-optimism.jpg └── vercel.svg ├── sentry.client.config.js ├── sentry.edge.config.js ├── sentry.properties ├── sentry.server.config.js ├── styles ├── Home.module.css ├── Reliquary.module.css ├── chakraTheme.ts ├── globals.css ├── nprogress.css └── themes │ ├── fantomTheme.ts │ └── optimismTheme.ts ├── tsconfig.json ├── types └── react-table-config.d.ts └── yarn.lock /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/issue-to-project.yml: -------------------------------------------------------------------------------- 1 | name: All all issues to project 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@v0.3.0 14 | with: 15 | project-url: https://github.com/orgs/beethovenxfi/projects/1 16 | github-token: ${{ secrets.ISSUETOPROJECT }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | .next 15 | .vscode 16 | 17 | # production 18 | /build 19 | 20 | # misc 21 | .DS_Store 22 | *.pem 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | .pnpm-debug.log* 29 | 30 | # local env files 31 | .env*.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | 39 | .env 40 | .idea 41 | 42 | # Sentry 43 | .sentryclirc -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 4, 4 | "singleQuote": true, 5 | "jsxSingleQuote": false, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Beets 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Beets FE V2 2 | -------------------------------------------------------------------------------- /assets/icons/chevron_down3.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/icons/chevron_down3.svg -------------------------------------------------------------------------------- /assets/icons/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/icons/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/beets-token-info-OP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/beets-token-info-OP.png -------------------------------------------------------------------------------- /assets/images/beets-token-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/beets-token-info.png -------------------------------------------------------------------------------- /assets/images/degen-band.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/degen-band.png -------------------------------------------------------------------------------- /assets/images/fantom-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/fantom-logo.png -------------------------------------------------------------------------------- /assets/images/footer-OP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/footer-OP.png -------------------------------------------------------------------------------- /assets/images/invest-masthead-image-OP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/invest-masthead-image-OP.png -------------------------------------------------------------------------------- /assets/images/invest-masthead-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/invest-masthead-image.png -------------------------------------------------------------------------------- /assets/images/optimism.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/images/pool-owner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/pool-owner.png -------------------------------------------------------------------------------- /assets/images/reliquary/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/1.png -------------------------------------------------------------------------------- /assets/images/reliquary/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/10.png -------------------------------------------------------------------------------- /assets/images/reliquary/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/11.png -------------------------------------------------------------------------------- /assets/images/reliquary/1x1-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/1x1-transparent.png -------------------------------------------------------------------------------- /assets/images/reliquary/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/2.png -------------------------------------------------------------------------------- /assets/images/reliquary/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/3.png -------------------------------------------------------------------------------- /assets/images/reliquary/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/4.png -------------------------------------------------------------------------------- /assets/images/reliquary/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/5.png -------------------------------------------------------------------------------- /assets/images/reliquary/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/6.png -------------------------------------------------------------------------------- /assets/images/reliquary/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/7.png -------------------------------------------------------------------------------- /assets/images/reliquary/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/8.png -------------------------------------------------------------------------------- /assets/images/reliquary/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/9.png -------------------------------------------------------------------------------- /assets/images/reliquary/approve-beets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/approve-beets.png -------------------------------------------------------------------------------- /assets/images/reliquary/approve-deposit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/approve-deposit.png -------------------------------------------------------------------------------- /assets/images/reliquary/approve-relayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/approve-relayer.png -------------------------------------------------------------------------------- /assets/images/reliquary/approve-relic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/approve-relic.png -------------------------------------------------------------------------------- /assets/images/reliquary/approve-vault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/approve-vault.png -------------------------------------------------------------------------------- /assets/images/reliquary/approve-wftm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/approve-wftm.png -------------------------------------------------------------------------------- /assets/images/reliquary/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/background.png -------------------------------------------------------------------------------- /assets/images/reliquary/complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/complete.png -------------------------------------------------------------------------------- /assets/images/reliquary/create-relic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/create-relic.png -------------------------------------------------------------------------------- /assets/images/reliquary/finished-relic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/finished-relic.png -------------------------------------------------------------------------------- /assets/images/reliquary/migrate-legacy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/migrate-legacy.png -------------------------------------------------------------------------------- /assets/images/reliquary/migrate-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/migrate-process.png -------------------------------------------------------------------------------- /assets/images/reliquary/migrated-minted-fbeets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/migrated-minted-fbeets.png -------------------------------------------------------------------------------- /assets/images/reliquary/unstake-fbeets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/reliquary/unstake-fbeets.png -------------------------------------------------------------------------------- /assets/images/rq-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/rq-1.png -------------------------------------------------------------------------------- /assets/images/rq-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/rq-2.png -------------------------------------------------------------------------------- /assets/images/rq-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/rq-3.png -------------------------------------------------------------------------------- /assets/images/sFTMx-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/sFTMx-header.png -------------------------------------------------------------------------------- /assets/images/swap-masthead-image-OP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/swap-masthead-image-OP.png -------------------------------------------------------------------------------- /assets/images/swap-masthead-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/swap-masthead-image.png -------------------------------------------------------------------------------- /assets/images/why-us-OP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/why-us-OP.png -------------------------------------------------------------------------------- /assets/images/why-us.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/images/why-us.png -------------------------------------------------------------------------------- /assets/logo/aura_iso_colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/logo/aura_iso_colors.png -------------------------------------------------------------------------------- /assets/logo/fmoney-pfp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/logo/fmoney-pfp.png -------------------------------------------------------------------------------- /assets/logo/gyro-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/logo/gyro-white.png -------------------------------------------------------------------------------- /assets/logo/merkl2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/assets/logo/merkl2x.png -------------------------------------------------------------------------------- /components/animated-progress/AnimatedProgress.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps } from '@chakra-ui/layout'; 2 | import { motion } from 'framer-motion'; 3 | import React, { ReactNode } from 'react'; 4 | import { BeetsBox } from '../box/BeetsBox'; 5 | 6 | interface Props { 7 | value: number; 8 | children?: ReactNode | ReactNode[]; 9 | } 10 | 11 | export default function AnimatedProgress({ value, children, ...rest }: Props & BoxProps) { 12 | return ( 13 | 14 | 26 | 27 | {children} 28 | 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /components/animation/FadeInBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps } from '@chakra-ui/react'; 2 | import { motion } from 'framer-motion'; 3 | 4 | interface Props extends BoxProps { 5 | isVisible: boolean; 6 | } 7 | 8 | export function FadeInBox({ children, isVisible, ...rest }: Props) { 9 | return ( 10 | <> 11 | {isVisible && ( 12 | 13 | {children} 14 | 15 | )} 16 | 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /components/animation/FadeInOutBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps } from '@chakra-ui/react'; 2 | import { AnimatePresence, motion } from 'framer-motion'; 3 | 4 | interface Props extends BoxProps { 5 | isVisible: boolean; 6 | containerWidth?: string; 7 | } 8 | 9 | export function FadeInOutBox({ children, isVisible, containerWidth, ...rest }: Props) { 10 | return ( 11 | 12 | {isVisible && ( 13 | 19 | {children} 20 | 21 | )} 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /components/animation/chakra.tsx: -------------------------------------------------------------------------------- 1 | import { chakra } from '@chakra-ui/system'; 2 | import { isValidMotionProp, motion } from 'framer-motion'; 3 | 4 | export const AnimatedBox = chakra(motion.div, { 5 | shouldForwardProp: (prop) => isValidMotionProp(prop) || prop === 'children', 6 | }); 7 | 8 | export const AnimatedButton = chakra(motion.button, { 9 | shouldForwardProp: (prop) => isValidMotionProp(prop) || prop === 'children', 10 | }); -------------------------------------------------------------------------------- /components/apr-tooltip/AprText.tsx: -------------------------------------------------------------------------------- 1 | import { Text, TextProps } from '@chakra-ui/react'; 2 | 3 | interface Props extends TextProps {} 4 | 5 | export function AprText({ children, ...rest }: Props) { 6 | return ( 7 | 8 | {children} 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /components/avatar/WalletUserAvatar.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | import BeetsSmart from '~/assets/icons/beetx-smarts.svg'; 3 | import { useEarlyLudwigNft } from '~/lib/global/useEarlyLudwigNft'; 4 | import { Image as ChakraImage } from '@chakra-ui/react'; 5 | 6 | export function WalletUserAvatar() { 7 | const { data } = useEarlyLudwigNft(); 8 | 9 | if (data) { 10 | return ; 11 | } 12 | 13 | return your-profile; 14 | } 15 | -------------------------------------------------------------------------------- /components/badge/PercentChangeBadge.tsx: -------------------------------------------------------------------------------- 1 | import { Badge } from '@chakra-ui/layout'; 2 | import numeral from 'numeral'; 3 | import { BadgeProps } from '@chakra-ui/react'; 4 | 5 | interface Props extends BadgeProps { 6 | percentChange: number; 7 | } 8 | 9 | export function PercentChangeBadge({ percentChange, ...rest }: Props) { 10 | return ( 11 | = 0 ? 'green' : 'red'} {...rest}> 12 | {numeral(percentChange).format('0.00%')} 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /components/box/BeetsBox.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps } from '@chakra-ui/react'; 2 | 3 | interface Props extends BoxProps {} 4 | 5 | export function BeetsBox({ children, ...rest }: Props) { 6 | return ( 7 | 8 | {children} 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /components/box/BeetsBoxHeader.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Flex, Text, BoxProps } from '@chakra-ui/react'; 2 | 3 | export function BeetsBoxHeader(props: BoxProps) { 4 | return ( 5 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /components/box/BeetsBoxLineItem.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps, Flex, FlexProps } from '@chakra-ui/react'; 2 | import { ReactNode } from 'react'; 3 | 4 | interface Props extends BoxProps { 5 | leftContent: ReactNode; 6 | rightContent: ReactNode; 7 | last?: boolean; 8 | center?: boolean; 9 | } 10 | 11 | export function BeetsBoxLineItem({ leftContent, rightContent, last, children, center, ...rest }: Props) { 12 | return ( 13 | 14 | 15 | 16 | {leftContent} 17 | 18 | {rightContent} 19 | 20 | {children} 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /components/bridge/useBeetsBalance.tsx: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | import { useUserBalances } from '~/lib/user/useUserBalances'; 3 | import { keyBy } from 'lodash'; 4 | import { parseUnits } from 'ethers/lib/utils.js'; 5 | 6 | export function useBeetsBalance() { 7 | const networkConfig = useNetworkConfig(); 8 | const { 9 | userBalances: balances = [], 10 | isLoading: isLoadingBalances, 11 | refetch, 12 | } = useUserBalances([networkConfig.beets.address]); 13 | 14 | const userBalancesMap = keyBy(balances, 'address'); 15 | const beetsBalance = userBalancesMap[networkConfig.beets.address]?.amount || '0'; 16 | 17 | return { 18 | balance: beetsBalance, 19 | isLoading: isLoadingBalances, 20 | hasBalance: parseUnits(beetsBalance, 18).gt(parseUnits('0.000001', 18)), // bridging thru stargate leaves some dust 21 | refetch, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /components/button/BeetsBatchRelayerApprovalButton.tsx: -------------------------------------------------------------------------------- 1 | import { BeetsSubmitTransactionButton } from '~/components/button/BeetsSubmitTransactionButton'; 2 | import { useApproveBatchRelayer } from '~/lib/util/useApproveBatchRelayer'; 3 | 4 | interface Props { 5 | contractToApprove?: string; 6 | onConfirmed?: () => void; 7 | onPending?: () => void; 8 | onSubmitting?: () => void; 9 | onCanceled?: () => void; 10 | isDisabled?: boolean; 11 | size?: string; 12 | buttonText?: string; 13 | } 14 | 15 | export function BeetsBatchRelayerApprovalButton({ buttonText, ...rest }: Props) { 16 | const { approve, ...query } = useApproveBatchRelayer(); 17 | 18 | return ( 19 | { 23 | approve(); 24 | }} 25 | {...rest} 26 | borderColor="beets.green" 27 | _focus={{ boxShadow: 'none' }} 28 | submittingText="Confirm..." 29 | pendingText="Waiting..." 30 | > 31 | {buttonText ? buttonText : 'Approve Batch Relayer'} 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /components/button/BeetsMinterApprovalButton.tsx: -------------------------------------------------------------------------------- 1 | import { BeetsSubmitTransactionButton } from '~/components/button/BeetsSubmitTransactionButton'; 2 | import { useApproveMinter } from '~/lib/util/useApproveMinter'; 3 | 4 | interface Props { 5 | contractToApprove?: string; 6 | onConfirmed?: () => void; 7 | onPending?: () => void; 8 | onSubmitting?: () => void; 9 | onCanceled?: () => void; 10 | isDisabled?: boolean; 11 | size?: string; 12 | buttonText?: string; 13 | } 14 | 15 | export function BeetsMinterApprovalButton({ buttonText, ...rest }: Props) { 16 | const { approve, ...query } = useApproveMinter(); 17 | 18 | return ( 19 | { 23 | approve(); 24 | }} 25 | {...rest} 26 | borderColor="beets.green" 27 | _focus={{ boxShadow: 'none' }} 28 | submittingText="Confirm..." 29 | pendingText="Waiting..." 30 | > 31 | {buttonText ? buttonText : 'Approve Batch Relayer for minting'} 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /components/button/BeetsTokenApprovalButton.tsx: -------------------------------------------------------------------------------- 1 | import { TokenBaseWithAmount } from '~/lib/services/token/token-types'; 2 | import { useApproveToken } from '~/lib/util/useApproveToken'; 3 | import { BeetsSubmitTransactionButton } from '~/components/button/BeetsSubmitTransactionButton'; 4 | import { networkConfig } from '~/lib/config/network-config'; 5 | 6 | interface Props { 7 | tokenWithAmount: TokenBaseWithAmount; 8 | contractToApprove?: string; 9 | onConfirmed?: () => void; 10 | onPending?: () => void; 11 | onSubmitting?: () => void; 12 | onCanceled?: () => void; 13 | isDisabled?: boolean; 14 | size?: string; 15 | inline?: boolean; 16 | isLoading?: boolean; 17 | } 18 | 19 | export function BeetsTokenApprovalButton({ 20 | tokenWithAmount, 21 | contractToApprove = networkConfig.balancer.vault, 22 | ...rest 23 | }: Props) { 24 | const { approve, ...query } = useApproveToken(tokenWithAmount); 25 | 26 | return ( 27 | { 31 | approve(contractToApprove); 32 | }} 33 | {...rest} 34 | > 35 | Approve {tokenWithAmount.symbol} 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /components/card/CardRow.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Flex, FlexProps } from '@chakra-ui/react'; 2 | 3 | export function CardRow(props: FlexProps) { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /components/fallback/FallbackPlaceholder.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Spinner } from '@chakra-ui/react'; 2 | 3 | export function FallbackPlaceholder() { 4 | return ( 5 | 6 | 7 | Loading... 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /components/icons/IconGithub.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Icon, IconProps } from '@chakra-ui/react'; 3 | 4 | export function IconGithub(props: IconProps) { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /components/icons/IconGlobe.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Icon, IconProps } from '@chakra-ui/react'; 3 | 4 | export function IconGlobe(props: IconProps) { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /components/icons/IconTelegram.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Icon, IconProps } from '@chakra-ui/react'; 3 | 4 | export function IconTelegram(props: IconProps) { 5 | return ( 6 | 7 | 8 | 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /components/icons/IconTwitter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Icon, IconProps } from '@chakra-ui/react'; 3 | 4 | export function IconTwitter(props: IconProps) { 5 | return ( 6 | 7 | 8 | 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /components/inputs/PresetSelector.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@chakra-ui/button'; 2 | import { HStack } from '@chakra-ui/layout'; 3 | 4 | type Preset = { 5 | label: string; 6 | value: number; 7 | }; 8 | interface Props { 9 | onPresetSelected: (preset: number) => void; 10 | presets?: Preset[]; 11 | } 12 | 13 | const defaultPresets = [ 14 | { 15 | label: '25%', 16 | value: 0.25, 17 | }, 18 | { 19 | label: '50%', 20 | value: 0.5, 21 | }, 22 | { 23 | label: '75%', 24 | value: 0.75, 25 | }, 26 | { 27 | label: '100%', 28 | value: 1, 29 | }, 30 | ]; 31 | export default function PresetSelector({ onPresetSelected, presets = defaultPresets }: Props) { 32 | const handlePresetSelected = (preset: number) => () => { 33 | onPresetSelected(preset); 34 | }; 35 | return ( 36 | 37 | {presets.map((preset) => ( 38 | 47 | ))} 48 | 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /components/link/NextLink.tsx: -------------------------------------------------------------------------------- 1 | import { Link as ChakraLink, LinkProps as ChakraLinkProps, LinkOverlay, LinkOverlayProps } from '@chakra-ui/react'; 2 | import Link, { LinkProps } from 'next/link'; 3 | import React from 'react'; 4 | 5 | export function NextLink({ 6 | children, 7 | chakraProps, 8 | ...rest 9 | }: React.PropsWithChildren & { chakraProps?: ChakraLinkProps }) { 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | } 16 | 17 | export function NextLinkOverlay({ 18 | children, 19 | chakraProps, 20 | ...rest 21 | }: React.PropsWithChildren & { chakraProps?: LinkOverlayProps }) { 22 | return ( 23 | 24 | {children} 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /components/masthead/PageMasthead.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Flex, Text } from '@chakra-ui/react'; 2 | import { ReactNode } from 'react'; 3 | 4 | interface Props { 5 | title: string; 6 | image: ReactNode; 7 | } 8 | 9 | export function PageMasthead({ title, image }: Props) { 10 | return ( 11 | 17 | 18 | {title} 19 | 20 | 21 | {image} 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /components/modal/ModalSectionHeadline.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps, Text } from '@chakra-ui/react'; 2 | 3 | interface Props extends BoxProps { 4 | headline: string; 5 | description?: string; 6 | } 7 | 8 | export function ModalSectionHeadline({ headline, description, ...rest }: Props) { 9 | return ( 10 | 11 | 12 | {headline} 13 | 14 | {description} 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /components/pool-badge/assets/badge-experimental.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/badge-experimental.gif -------------------------------------------------------------------------------- /components/pool-badge/assets/boosted-by-beefy-exactly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/boosted-by-beefy-exactly.png -------------------------------------------------------------------------------- /components/pool-badge/assets/built-by-gyroscope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/built-by-gyroscope.png -------------------------------------------------------------------------------- /components/pool-badge/assets/overnight-boosted-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/overnight-boosted-small.png -------------------------------------------------------------------------------- /components/pool-badge/assets/reaper-aave-boosted-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/reaper-aave-boosted-small.png -------------------------------------------------------------------------------- /components/pool-badge/assets/reaper-aave-granary-boosted-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/reaper-aave-granary-boosted-small.png -------------------------------------------------------------------------------- /components/pool-badge/assets/reaper-boosted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/reaper-boosted.png -------------------------------------------------------------------------------- /components/pool-badge/assets/reaper-sonne-boosted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/components/pool-badge/assets/reaper-sonne-boosted.png -------------------------------------------------------------------------------- /components/popup-menu/TextButtonPopupMenu.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/react'; 2 | import { Check } from 'react-feather'; 3 | 4 | interface Props { 5 | buttonText: string; 6 | items: { 7 | label: string; 8 | selected?: boolean; 9 | onClick: () => void; 10 | }[]; 11 | } 12 | 13 | export function TextButtonPopupMenu({ buttonText, items }: Props) { 14 | return ( 15 | 16 | 23 | {buttonText} 24 | 25 | 26 | {items.map((item, index) => ( 27 | 28 | {item.label} 29 | {item.selected ? : null} 30 | 31 | ))} 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /components/providers/Compose.tsx: -------------------------------------------------------------------------------- 1 | export type ProviderWithProps = [React.JSXElementConstructor>, any]; 2 | interface Props { 3 | providers: Array; 4 | children: React.ReactNode; 5 | 6 | } 7 | 8 | export default function Compose(props: Props) { 9 | const { providers = [], children } = props; 10 | 11 | return ( 12 | <> 13 | {providers.reduceRight((acc, prov) => { 14 | const Provider = prov[0]; 15 | return {acc}; 16 | }, children)} 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /components/tabs/BeetsTab.tsx: -------------------------------------------------------------------------------- 1 | import { Button, TabProps, HStack, Tab, Text, useTab, useMultiStyleConfig, Box } from '@chakra-ui/react'; 2 | import { AnimatePresence } from 'framer-motion'; 3 | import { forwardRef } from 'react'; 4 | import { Eye } from 'react-feather'; 5 | import { AnimatedBox } from '~/components/animation/chakra'; 6 | 7 | const BeetsTab = forwardRef((props: { children: any } & TabProps, ref: any) => { 8 | const tabProps = useTab({ ...props, ref }); 9 | const isSelected = !!tabProps['aria-selected']; 10 | 11 | return ( 12 | 30 | ); 31 | }); 32 | 33 | BeetsTab.displayName = 'BeetsTab'; 34 | export default BeetsTab; 35 | -------------------------------------------------------------------------------- /components/token-select/TokenActionRow.tsx: -------------------------------------------------------------------------------- 1 | import { Button, ButtonProps } from '@chakra-ui/button'; 2 | import { Box, HStack, Text } from '@chakra-ui/layout'; 3 | import TokenAvatar from '~/components/token/TokenAvatar'; 4 | import { TokenBase } from '~/lib/services/token/token-types'; 5 | import { LinkProps } from '@chakra-ui/react'; 6 | 7 | type TokenRowProps = TokenBase & { 8 | index: number; 9 | action: 'import' | 'remove'; 10 | }; 11 | 12 | export function TokenActionRow({ symbol, address, onClick, action }: TokenRowProps & ButtonProps & LinkProps) { 13 | return ( 14 | 15 | 16 | 17 | 18 | {symbol} 19 | 20 | 21 | 24 | 25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /components/token-select/TokenSelectSearchInput.tsx: -------------------------------------------------------------------------------- 1 | import { forwardRef, Input, InputGroup, InputLeftElement, useTheme } from '@chakra-ui/react'; 2 | import { Search } from 'react-feather'; 3 | 4 | interface Props { 5 | placeholder: string; 6 | value: string; 7 | setValue: (value: string) => void; 8 | } 9 | 10 | export const TokenSelectSearchInput = forwardRef(({ value, setValue, placeholder }: Props, ref) => { 11 | const { colors } = useTheme(); 12 | 13 | return ( 14 | 15 | 16 | 17 | 18 | setValue(e.currentTarget.value)} 25 | /> 26 | 27 | ); 28 | }); 29 | -------------------------------------------------------------------------------- /components/token/TokenAmountPill.tsx: -------------------------------------------------------------------------------- 1 | import { BeetsBox } from '~/components/box/BeetsBox'; 2 | import TokenAvatar from '~/components/token/TokenAvatar'; 3 | import { Flex, Text, BoxProps } from '@chakra-ui/react'; 4 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 5 | import { tokenFormatAmount, tokenFormatAmountPrecise } from '~/lib/services/token/token-util'; 6 | 7 | interface Props extends BoxProps { 8 | address: string; 9 | amount: AmountHumanReadable; 10 | amountFormat?: 'standard' | 'precise'; 11 | } 12 | 13 | export function TokenAmountPill({ address, amount, amountFormat = 'standard', ...rest }: Props) { 14 | return ( 15 | 16 | 17 | 18 | 19 | {amountFormat === 'precise' ? tokenFormatAmountPrecise(amount) : tokenFormatAmount(amount)} 20 | 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /components/token/TokenAvatar.tsx: -------------------------------------------------------------------------------- 1 | import { Avatar, AvatarProps, Circle } from '@chakra-ui/react'; 2 | import { useGetTokens } from '~/lib/global/useToken'; 3 | import Jazzicon, { jsNumberForAddress } from 'react-jazzicon'; 4 | import { AddressZero } from '@ethersproject/constants'; 5 | 6 | interface Props extends AvatarProps { 7 | address?: string | null; 8 | logoURI?: string; 9 | } 10 | 11 | function TokenAvatar({ address, size, logoURI, ...rest }: Props) { 12 | const { getToken } = useGetTokens(); 13 | const token = address ? getToken(address) : null; 14 | 15 | return ( 16 | 24 | ) : ( 25 | 29 | ) 30 | } 31 | /> 32 | ); 33 | } 34 | 35 | export default TokenAvatar; 36 | -------------------------------------------------------------------------------- /components/tooltip/BeetsTooltip.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react'; 2 | import { Box, HStack, Text } from '@chakra-ui/layout'; 3 | import { Tooltip } from '@chakra-ui/tooltip'; 4 | import BeetsThinking from '~/assets/icons/beetx-thinking.svg'; 5 | import Image from 'next/image'; 6 | 7 | interface Props { 8 | children: ReactNode | ReactNode[]; 9 | label: ReactNode | ReactNode[] | null; 10 | noImage?: boolean; 11 | hasArrow?: boolean; 12 | } 13 | 14 | function BeetsTooltipLabel({ label, noImage }: { label: ReactNode | ReactNode[]; noImage: boolean }) { 15 | return ( 16 | 17 | {!noImage && ( 18 | 19 | thinking-emoji 20 | 21 | )} 22 | {label} 23 | 24 | ); 25 | } 26 | 27 | export default function BeetsTooltip({ children, label, noImage, hasArrow = false }: Props) { 28 | if (!label) return <>{children}; 29 | 30 | return ( 31 | } 37 | hasArrow={hasArrow} 38 | > 39 | {children} 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /components/typography/BeetsHeadline.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps } from '@chakra-ui/react'; 2 | import { ReactNode } from 'react'; 3 | 4 | interface Props extends BoxProps { 5 | children: ReactNode; 6 | } 7 | 8 | export function BeetsHeadline({ children, ...rest }: Props) { 9 | return ( 10 | 11 | {children} 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /components/typography/BeetsSubHeadline.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps, Text } from '@chakra-ui/react'; 2 | import { ReactNode } from 'react'; 3 | 4 | interface Props extends BoxProps { 5 | children: ReactNode; 6 | } 7 | 8 | export function BeetsSubHeadline({ children, ...rest }: Props) { 9 | return ( 10 | 11 | {children} 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /components/user-warning/UserWarning.tsx: -------------------------------------------------------------------------------- 1 | import { useUserData } from '~/lib/user/useUserData'; 2 | import { ToastType, useToast } from '~/components/toast/BeetsToast'; 3 | import { useEffect } from 'react'; 4 | import { Box, Button, HStack, Link } from '@chakra-ui/react'; 5 | import { networkConfig } from '~/lib/config/network-config'; 6 | 7 | export function UserWarning() { 8 | const { usdBalanceForPool } = useUserData(); 9 | const { showToast } = useToast(); 10 | 11 | const poolList = Object.keys(networkConfig.warnings.poolList); 12 | const userHasFundsAtRisk = poolList.find((pooliD) => usdBalanceForPool(pooliD) > 0); 13 | 14 | useEffect(() => { 15 | if (userHasFundsAtRisk) { 16 | showToast({ 17 | id: 'user-funds-alert', 18 | type: ToastType.Warn, 19 | content: ( 20 | 21 | 22 | You are invested in a pool with a known vulnerability. Please remove liquidity from the 23 | affected pool(s) immediately. 24 | 25 | 26 | ), 27 | }); 28 | } 29 | }, [userHasFundsAtRisk]); 30 | 31 | return null; 32 | } 33 | -------------------------------------------------------------------------------- /declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-virtual-list'; -------------------------------------------------------------------------------- /lib/abi/BasePoolFactory.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "pool", 9 | "type": "address" 10 | } 11 | ], 12 | "name": "PoolRegistered", 13 | "type": "event" 14 | }, 15 | { 16 | "inputs": [], 17 | "name": "vault", 18 | "outputs": [ 19 | { 20 | "internalType": "contract IVault", 21 | "name": "", 22 | "type": "address" 23 | } 24 | ], 25 | "stateMutability": "view", 26 | "type": "function" 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /lib/abi/BatchRelayer.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IVault", 6 | "name": "vault", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "libraryAddress", 12 | "type": "address" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "getLibrary", 21 | "outputs": [ 22 | { 23 | "internalType": "address", 24 | "name": "", 25 | "type": "address" 26 | } 27 | ], 28 | "stateMutability": "view", 29 | "type": "function" 30 | }, 31 | { 32 | "inputs": [], 33 | "name": "getVault", 34 | "outputs": [ 35 | { 36 | "internalType": "contract IVault", 37 | "name": "", 38 | "type": "address" 39 | } 40 | ], 41 | "stateMutability": "view", 42 | "type": "function" 43 | }, 44 | { 45 | "inputs": [ 46 | { 47 | "internalType": "bytes[]", 48 | "name": "data", 49 | "type": "bytes[]" 50 | } 51 | ], 52 | "name": "multicall", 53 | "outputs": [ 54 | { 55 | "internalType": "bytes[]", 56 | "name": "results", 57 | "type": "bytes[]" 58 | } 59 | ], 60 | "stateMutability": "payable", 61 | "type": "function" 62 | }, 63 | { 64 | "stateMutability": "payable", 65 | "type": "receive" 66 | } 67 | ] 68 | -------------------------------------------------------------------------------- /lib/abi/BatchRelayerLibrary.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "getEntrypoint", 5 | "outputs": [{ "internalType": "contract IBalancerRelayer", "name": "", "type": "address" }], 6 | "stateMutability": "view", 7 | "type": "function" 8 | }, 9 | { 10 | "inputs": [], 11 | "name": "getVault", 12 | "outputs": [{ "internalType": "contract IVault", "name": "", "type": "address" }], 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "inputs": [{ "internalType": "uint256", "name": "ref", "type": "uint256" }], 18 | "name": "peekChainedReferenceValue", 19 | "outputs": [{ "internalType": "uint256", "name": "value", "type": "uint256" }], 20 | "stateMutability": "view", 21 | "type": "function" 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /lib/abi/BeethovenCheckpointer.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [{ "internalType": "address[]", "name": "gauges_to_checkpoint", "type": "address[]" }], 4 | "name": "checkpoint_my_gauges", 5 | "outputs": [], 6 | "stateMutability": "nonpayable", 7 | "type": "function" 8 | }, 9 | { 10 | "inputs": [ 11 | { "internalType": "address", "name": "user", "type": "address" }, 12 | { "internalType": "address[]", "name": "gauges_to_checkpoint", "type": "address[]" } 13 | ], 14 | "name": "checkpoint_user_gauges", 15 | "outputs": [], 16 | "stateMutability": "nonpayable", 17 | "type": "function" 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /lib/abi/ChildChainGaugeRewardHelper.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "name": "CLAIM_FREQUENCY", 5 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 6 | "stateMutability": "view", 7 | "type": "function" 8 | }, 9 | { 10 | "inputs": [], 11 | "name": "CLAIM_SIG", 12 | "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "inputs": [ 18 | { 19 | "internalType": "contract IRewardsOnlyGauge", 20 | "name": "gauge", 21 | "type": "address" 22 | }, 23 | { "internalType": "address", "name": "user", "type": "address" } 24 | ], 25 | "name": "claimRewards", 26 | "outputs": [], 27 | "stateMutability": "nonpayable", 28 | "type": "function" 29 | }, 30 | { 31 | "inputs": [ 32 | { 33 | "internalType": "contract IRewardsOnlyGauge", 34 | "name": "gauge", 35 | "type": "address" 36 | }, 37 | { "internalType": "address", "name": "user", "type": "address" }, 38 | { "internalType": "address", "name": "token", "type": "address" } 39 | ], 40 | "name": "pendingRewards", 41 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 42 | "stateMutability": "nonpayable", 43 | "type": "function" 44 | } 45 | ] 46 | -------------------------------------------------------------------------------- /lib/abi/LinearPoolRebalancer.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { "internalType": "contract IVault", "name": "vault", "type": "address" }, 5 | { "internalType": "contract IBalancerQueries", "name": "queries", "type": "address" } 6 | ], 7 | "stateMutability": "nonpayable", 8 | "type": "constructor" 9 | }, 10 | { 11 | "inputs": [], 12 | "name": "getPool", 13 | "outputs": [{ "internalType": "contract ILinearPool", "name": "", "type": "address" }], 14 | "stateMutability": "view", 15 | "type": "function" 16 | }, 17 | { 18 | "inputs": [{ "internalType": "address", "name": "recipient", "type": "address" }], 19 | "name": "rebalance", 20 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 21 | "stateMutability": "nonpayable", 22 | "type": "function" 23 | }, 24 | { 25 | "inputs": [ 26 | { "internalType": "address", "name": "recipient", "type": "address" }, 27 | { "internalType": "uint256", "name": "extraMain", "type": "uint256" } 28 | ], 29 | "name": "rebalanceWithExtraMain", 30 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 31 | "stateMutability": "nonpayable", 32 | "type": "function" 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /lib/abi/StaticATokenRateProvider.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "contract IStaticAToken", 6 | "name": "_waToken", 7 | "type": "address" 8 | } 9 | ], 10 | "stateMutability": "nonpayable", 11 | "type": "constructor" 12 | }, 13 | { 14 | "inputs": [], 15 | "name": "getRate", 16 | "outputs": [ 17 | { 18 | "internalType": "uint256", 19 | "name": "", 20 | "type": "uint256" 21 | } 22 | ], 23 | "stateMutability": "view", 24 | "type": "function" 25 | }, 26 | { 27 | "inputs": [], 28 | "name": "waToken", 29 | "outputs": [ 30 | { 31 | "internalType": "contract IStaticAToken", 32 | "name": "", 33 | "type": "address" 34 | } 35 | ], 36 | "stateMutability": "view", 37 | "type": "function" 38 | } 39 | ] 40 | -------------------------------------------------------------------------------- /lib/config/network-config.ts: -------------------------------------------------------------------------------- 1 | import { NetworkConfig } from '~/lib/config/network-config-type'; 2 | import { fantomNetworkConfig } from '~/lib/config/fantom'; 3 | import { optimismNetworkConfig } from '~/lib/config/optimism'; 4 | 5 | const AllNetworkConfigs: { [chainId: string]: NetworkConfig } = { 6 | '250': fantomNetworkConfig, 7 | '10': optimismNetworkConfig, 8 | }; 9 | 10 | export const networkConfig = AllNetworkConfigs[process.env.NEXT_PUBLIC_CHAIN_ID || '250']; 11 | 12 | export const networkList = [ 13 | { 14 | name: fantomNetworkConfig.networkShortName, 15 | chainId: fantomNetworkConfig.chainId, 16 | url: 'https://beets.fi', 17 | iconUrl: fantomNetworkConfig.eth.iconUrl, 18 | }, 19 | { 20 | name: optimismNetworkConfig.networkShortName, 21 | chainId: optimismNetworkConfig.chainId, 22 | url: 'https://op.beets.fi', 23 | iconUrl: optimismNetworkConfig.eth.iconUrl, 24 | }, 25 | ]; 26 | -------------------------------------------------------------------------------- /lib/global/constants.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | subgraphs: { 3 | 'mainnet-gauge': 'https://api.studio.thegraph.com/query/75376/balancer-gauges/version/latest', 4 | 'optimism-gauge': 'https://api.studio.thegraph.com/query/75376/balancer-gauges-optimism/version/latest', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /lib/global/useMasterChefHarvestAllRewards.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import BeethovenxMasterChefAbi from '~/lib/abi/BeethovenxMasterChef.json'; 3 | import { useUserAccount } from '~/lib/user/useUserAccount'; 4 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 5 | 6 | export function useMasterChefHarvestAllRewards() { 7 | const networkConfig = useNetworkConfig(); 8 | const { userAddress } = useUserAccount(); 9 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 10 | config: { 11 | addressOrName: networkConfig.masterChefContractAddress, 12 | contractInterface: BeethovenxMasterChefAbi, 13 | functionName: 'harvestAll', 14 | }, 15 | transactionType: 'HARVEST', 16 | }); 17 | 18 | function harvestAll(farmIds: string[]) { 19 | submit({ 20 | args: [farmIds, userAddress], 21 | toastText: 'Harvest all pending rewards', 22 | }); 23 | } 24 | 25 | return { 26 | harvestAll, 27 | ...rest, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /lib/global/useNetworkConfig.ts: -------------------------------------------------------------------------------- 1 | import { networkConfig } from '~/lib/config/network-config'; 2 | 3 | export function useNetworkConfig() { 4 | return networkConfig; 5 | } 6 | -------------------------------------------------------------------------------- /lib/global/useOldBeetsBalance.ts: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | import { useUserBalances } from '~/lib/user/useUserBalances'; 3 | import { keyBy } from 'lodash'; 4 | 5 | export function useOldBeetsBalance() { 6 | const networkConfig = useNetworkConfig(); 7 | const { userBalances: balances = [], isLoading: isLoadingBalances } = useUserBalances([ 8 | networkConfig.beets.oldAddress, 9 | ]); 10 | 11 | const userBalancesMap = keyBy(balances, 'address'); 12 | const oldBeetsBalance = userBalancesMap[networkConfig.beets.oldAddress]?.amount || '0'; 13 | 14 | return { 15 | balance: oldBeetsBalance, 16 | isLoading: isLoadingBalances, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /lib/global/useSlippage.ts: -------------------------------------------------------------------------------- 1 | import { makeVar, useReactiveVar } from '@apollo/client'; 2 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 3 | 4 | const SLIPPAGE_CACHE_KEY = 'SLIPPAGE'; 5 | const cached = typeof window !== 'undefined' ? localStorage.getItem(SLIPPAGE_CACHE_KEY) : null; 6 | 7 | const slippageVar = makeVar(cached || '0.005'); 8 | 9 | export function useSlippage() { 10 | const slippage = useReactiveVar(slippageVar); 11 | const slippageDifference = 1 - parseFloat(slippage); 12 | const slippageAddition = 1 + parseFloat(slippage); 13 | 14 | function setSlippage(amount: AmountHumanReadable) { 15 | slippageVar(amount); 16 | 17 | localStorage.setItem(SLIPPAGE_CACHE_KEY, amount); 18 | } 19 | 20 | return { 21 | slippage, 22 | slippageDifference, 23 | slippageAddition, 24 | setSlippage, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /lib/global/useSubgraphQuery.ts: -------------------------------------------------------------------------------- 1 | import { DocumentNode } from 'graphql'; 2 | import { QueryKey, QueryOptions, UseQueryOptions, useQuery } from 'react-query'; 3 | import axios from 'axios'; 4 | 5 | import constants from '~/lib/global/constants'; 6 | 7 | export type SupportedSubgraphs = 'mainnet-gauge' | 'optimism-gauge'; 8 | export type SubgraphResponse = { 9 | data: T; 10 | }; 11 | 12 | export default function useSubgraphQuery< 13 | T, 14 | TQueryFnData = T, 15 | TError = unknown, 16 | TData = T, 17 | TQueryKey extends QueryKey = QueryKey, 18 | >( 19 | subgraph: SupportedSubgraphs, 20 | query: DocumentNode, 21 | variables: any, 22 | options: Omit, 'queryKey' | 'queryFn'> = {}, 23 | ) { 24 | const queryString = query.loc?.source.body; 25 | const url = constants.subgraphs[subgraph]; 26 | const queryInstance = useQuery( 27 | ['subgraph-query', { subgraph, query: queryString, variables }] as any, 28 | async () => { 29 | const response = await axios.post>(url, { 30 | query: queryString, 31 | variables, 32 | }); 33 | 34 | return response.data.data; 35 | }, 36 | options as any, 37 | ); 38 | 39 | return queryInstance; 40 | } 41 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/aave-wrapping.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import aaveWrappingAbi from '~/lib/abi/AaveWrapping.json'; 3 | import { EncodeUnwrapAaveStaticTokenInput } from '~/lib/services/batch-relayer/relayer-types'; 4 | 5 | export class AaveWrappingService { 6 | public encodeUnwrap(params: EncodeUnwrapAaveStaticTokenInput): string { 7 | const aaveWrappingLibrary = new Interface(aaveWrappingAbi); 8 | 9 | return aaveWrappingLibrary.encodeFunctionData('unwrapAaveStaticToken', [ 10 | params.staticToken, 11 | params.sender, 12 | params.recipient, 13 | params.amount, 14 | params.toUnderlying, 15 | params.outputReferences, 16 | ]); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/boo-mirror-world-staking.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import booMirrorWorldStakingAbi from '~/lib/abi/BooMirrorWorldStaking.json'; 3 | import { 4 | EncodeBooMirrorWorldEnterInput, 5 | EncodeBooMirrorWorldLeaveInput, 6 | } from '~/lib/services/batch-relayer/relayer-types'; 7 | 8 | export class BooMirrorWorldStakingService { 9 | public encodeEnter(params: EncodeBooMirrorWorldEnterInput): string { 10 | const booMirrorWorldStakingLibrary = new Interface(booMirrorWorldStakingAbi); 11 | 12 | return booMirrorWorldStakingLibrary.encodeFunctionData('booMirrorWorldEnter', [ 13 | params.sender, 14 | params.recipient, 15 | params.amount, 16 | params.outputReference, 17 | ]); 18 | } 19 | 20 | public encodeLeave(params: EncodeBooMirrorWorldLeaveInput): string { 21 | const booMirrorWorldStakingLibrary = new Interface(booMirrorWorldStakingAbi); 22 | 23 | return booMirrorWorldStakingLibrary.encodeFunctionData('booMirrorWorldLeave', [ 24 | params.sender, 25 | params.recipient, 26 | params.amount, 27 | params.outputReference, 28 | ]); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/erc4626-wrapping.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import Erc4626WrappingAbi from '~/lib/abi/Erc4626Wrapping.json'; 3 | import { EncodeUnwrapErc4626Input, EncodeWrapErc4626Input } from '~/lib/services/batch-relayer/relayer-types'; 4 | 5 | export class Erc4626WrappingService { 6 | public encodeWrap(params: EncodeWrapErc4626Input): string { 7 | const erc4626WrappingLibrary = new Interface(Erc4626WrappingAbi); 8 | 9 | return erc4626WrappingLibrary.encodeFunctionData('wrapERC4626', [ 10 | params.wrappedToken, 11 | params.sender, 12 | params.recipient, 13 | params.amount, 14 | params.outputReference, 15 | ]); 16 | } 17 | 18 | public encodeUnwrap(params: EncodeUnwrapErc4626Input): string { 19 | const erc4626WrappingLibrary = new Interface(Erc4626WrappingAbi); 20 | 21 | return erc4626WrappingLibrary.encodeFunctionData('unwrapERC4626', [ 22 | params.wrappedToken, 23 | params.sender, 24 | params.recipient, 25 | params.amount, 26 | params.outputReference, 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/fbeets-bar-staking.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import fBeetsBarStakingAbi from '~/lib/abi/FBeetsBarStaking.json'; 3 | import { EncodeFBeetsBarEnterInput, EncodeFBeetsBarLeaveInput } from '~/lib/services/batch-relayer/relayer-types'; 4 | 5 | export class FBeetsBarStakingService { 6 | public encodeEnter(params: EncodeFBeetsBarEnterInput): string { 7 | const fBeetsBarStakingLibrary = new Interface(fBeetsBarStakingAbi); 8 | 9 | return fBeetsBarStakingLibrary.encodeFunctionData('fBeetsBarEnter', [ 10 | params.sender, 11 | params.recipient, 12 | params.amount, 13 | params.outputReference, 14 | ]); 15 | } 16 | 17 | public encodeLeave(params: EncodeFBeetsBarLeaveInput): string { 18 | const fBeetsBarStakingLibrary = new Interface(fBeetsBarStakingAbi); 19 | 20 | return fBeetsBarStakingLibrary.encodeFunctionData('fBeetsBarLeave', [ 21 | params.sender, 22 | params.recipient, 23 | params.amount, 24 | params.outputReference, 25 | ]); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/masterchef-staking.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import MasterChefStakingAbi from '~/lib/abi/MasterChefStaking.json'; 3 | import { 4 | EncodeMasterChefDepositInput, 5 | EncodeMasterChefWithdrawInput, 6 | } from '~/lib/services/batch-relayer/relayer-types'; 7 | 8 | export class MasterChefStakingService { 9 | public encodeDeposit(params: EncodeMasterChefDepositInput): string { 10 | const masterChefStakingLibrary = new Interface(MasterChefStakingAbi); 11 | 12 | return masterChefStakingLibrary.encodeFunctionData('masterChefDeposit', [ 13 | params.sender, 14 | params.recipient, 15 | params.token, 16 | params.pid, 17 | params.amount, 18 | params.outputReference, 19 | ]); 20 | } 21 | 22 | public encodeWithdraw(params: EncodeMasterChefWithdrawInput): string { 23 | const masterChefStakingLibrary = new Interface(MasterChefStakingAbi); 24 | 25 | return masterChefStakingLibrary.encodeFunctionData('masterChefWithdraw', [ 26 | params.recipient, 27 | params.pid, 28 | params.amount, 29 | params.outputReference, 30 | ]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/reaper-wrapping.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import ReaperWrappingAbi from '~/lib/abi/ReaperWrapping.json'; 3 | import { 4 | EncodeWrapReaperVaultTokenInput, 5 | EncodeUnwrapReaperVaultTokenInput, 6 | } from '~/lib/services/batch-relayer/relayer-types'; 7 | 8 | export class ReaperWrappingService { 9 | public encodeWrap(params: EncodeWrapReaperVaultTokenInput): string { 10 | const reaperWrappingLibrary = new Interface(ReaperWrappingAbi); 11 | 12 | return reaperWrappingLibrary.encodeFunctionData('wrapReaperVaultToken', [ 13 | params.vaultToken, 14 | params.sender, 15 | params.recipient, 16 | params.amount, 17 | params.outputReference, 18 | ]); 19 | } 20 | 21 | public encodeUnwrap(params: EncodeUnwrapReaperVaultTokenInput): string { 22 | const reaperWrappingLibrary = new Interface(ReaperWrappingAbi); 23 | 24 | return reaperWrappingLibrary.encodeFunctionData('unwrapReaperVaultToken', [ 25 | params.vaultToken, 26 | params.sender, 27 | params.recipient, 28 | params.amount, 29 | params.outputReference, 30 | ]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/tarot-supply-vault.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import tarotWrappingAbi from '~/lib/abi/TarotWrapping.json'; 3 | import { EncodeTarotEnterInput, EncodeTarotLeaveInput } from '~/lib/services/batch-relayer/relayer-types'; 4 | 5 | export class TarotSupplyVaultService { 6 | public encodeEnter(params: EncodeTarotEnterInput): string { 7 | const tarotWrappingLibrary = new Interface(tarotWrappingAbi); 8 | 9 | return tarotWrappingLibrary.encodeFunctionData('tarotSupplyVaultEnter', [ 10 | params.supplyVault, 11 | params.sender, 12 | params.recipient, 13 | params.amount, 14 | params.outputReference, 15 | ]); 16 | } 17 | 18 | public encodeLeave(params: EncodeTarotLeaveInput): string { 19 | const tarotWrappingLibrary = new Interface(tarotWrappingAbi); 20 | 21 | return tarotWrappingLibrary.encodeFunctionData('tarotSupplyVaultLeave', [ 22 | params.supplyVault, 23 | params.sender, 24 | params.recipient, 25 | params.amount, 26 | params.outputReference, 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/services/batch-relayer/extensions/yearn-wrapping.service.ts: -------------------------------------------------------------------------------- 1 | import { Interface } from '@ethersproject/abi'; 2 | import YearnWrappingAbi from '~/lib/abi/YearnWrapping.json'; 3 | import { EncodeUnwrapYearnVaultTokenInput } from '~/lib/services/batch-relayer/relayer-types'; 4 | 5 | export class YearnWrappingService { 6 | public encodeWrap(params: EncodeUnwrapYearnVaultTokenInput): string { 7 | const yearnWrappingLibrary = new Interface(YearnWrappingAbi); 8 | 9 | return yearnWrappingLibrary.encodeFunctionData('wrapYearnVaultToken', [ 10 | params.vaultToken, 11 | params.sender, 12 | params.recipient, 13 | params.amount, 14 | params.outputReference, 15 | ]); 16 | } 17 | 18 | public encodeUnwrap(params: EncodeUnwrapYearnVaultTokenInput): string { 19 | const yearnWrappingLibrary = new Interface(YearnWrappingAbi); 20 | 21 | return yearnWrappingLibrary.encodeFunctionData('unwrapYearnVaultToken', [ 22 | params.vaultToken, 23 | params.sender, 24 | params.recipient, 25 | params.amount, 26 | params.outputReference, 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/services/pool/pool-weighted-compose.service.ts: -------------------------------------------------------------------------------- 1 | import { PoolCreationToken } from '~/modules/compose/ComposeProvider'; 2 | import { PoolJoinContractCallData, PoolJoinData } from './pool-types'; 3 | import { poolScaleTokenAmounts } from './lib/util'; 4 | import { GqlPoolTokenBase, GqlToken } from '~/apollo/generated/graphql-codegen-generated'; 5 | import { WeightedPoolEncoder } from '@balancer-labs/balancer-js'; 6 | 7 | export class WeightedPoolComposeService { 8 | constructor() {} 9 | 10 | public joinGetContractCallData(tokenMetadata: GqlToken[], data: PoolJoinData): PoolJoinContractCallData { 11 | const assets = data.maxAmountsIn.map((token) => token.address); 12 | const maxAmountsIn = poolScaleTokenAmounts(data.maxAmountsIn, tokenMetadata); 13 | const userData = WeightedPoolEncoder.joinInit(maxAmountsIn); 14 | 15 | return { 16 | assets, 17 | maxAmountsIn, 18 | userData, 19 | type: 'JoinPool', 20 | }; 21 | } 22 | } 23 | 24 | export const weightedPoolComposeService = new WeightedPoolComposeService(); 25 | -------------------------------------------------------------------------------- /lib/services/rpc-provider/static-json-rpc-batch-provier.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from '@ethersproject/logger'; 2 | import { Network } from '@ethersproject/networks'; 3 | import { defineReadOnly } from '@ethersproject/properties'; 4 | import { logger, providers } from 'ethers'; 5 | 6 | export class StaticJsonRpcBatchProvider extends providers.JsonRpcBatchProvider { 7 | async detectNetwork(): Promise { 8 | let network = this.network; 9 | if (network == null) { 10 | network = await super.detectNetwork(); 11 | 12 | if (!network) { 13 | logger.throwError('no network detected', Logger.errors.UNKNOWN_ERROR, {}); 14 | } 15 | 16 | // If still not set, set it 17 | if (this._network == null) { 18 | // A static network does not support "any" 19 | defineReadOnly(this, '_network', network); 20 | 21 | this.emit('network', network, null); 22 | } 23 | } 24 | return network; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/services/staking/fresh-beets.service.ts: -------------------------------------------------------------------------------- 1 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 2 | import { BaseProvider } from '@ethersproject/providers'; 3 | import { masterChefService, MasterChefService } from '~/lib/services/staking/master-chef.service'; 4 | import { oldBnumScaleAmount, oldBnumToHumanReadable } from '~/lib/services/pool/lib/old-big-number'; 5 | 6 | interface GetUserStakedBalanceInput { 7 | userAddress: string; 8 | farmId: string; 9 | provider: BaseProvider; 10 | fBeetsRatio: string; 11 | } 12 | 13 | export class FreshBeetsService { 14 | constructor(private readonly masterChefService: MasterChefService) {} 15 | 16 | public async getUserStakedBalance({ 17 | userAddress, 18 | farmId, 19 | provider, 20 | fBeetsRatio, 21 | }: GetUserStakedBalanceInput): Promise { 22 | const stakedFbeets = await this.masterChefService.getUserStakedBalance({ provider, farmId, userAddress }); 23 | 24 | return oldBnumToHumanReadable(oldBnumScaleAmount(stakedFbeets).times(fBeetsRatio)); 25 | } 26 | } 27 | 28 | export const freshBeetsService = new FreshBeetsService(masterChefService); 29 | -------------------------------------------------------------------------------- /lib/services/staking/staking-types.ts: -------------------------------------------------------------------------------- 1 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 2 | 3 | export interface StakingPendingRewardAmount { 4 | id: string; 5 | address: string; 6 | amount: AmountHumanReadable; 7 | } 8 | 9 | export interface ReliquaryStakingPendingRewardAmount extends StakingPendingRewardAmount { 10 | relicId: string; 11 | } 12 | -------------------------------------------------------------------------------- /lib/services/token/token-types.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from 'ethers'; 2 | 3 | export interface TokenAmountHumanReadable { 4 | address: string; 5 | amount: string; 6 | } 7 | 8 | export interface TokenAmountScaled { 9 | address: string; 10 | amount: BigNumber; 11 | } 12 | 13 | export interface TokenBase { 14 | address: string; 15 | name: string; 16 | symbol: string; 17 | decimals: number; 18 | } 19 | 20 | export interface TokenBaseWithAmount extends TokenBase { 21 | amount: string; 22 | } 23 | 24 | export type AmountHumanReadable = string; 25 | export type AmountScaled = BigNumber; 26 | export type AmountScaledString = string; 27 | 28 | export type BalanceMap = Map; 29 | 30 | export interface AmountHumanReadableMap { 31 | [address: string]: AmountHumanReadable; 32 | } 33 | -------------------------------------------------------------------------------- /lib/services/util/gas-price.service.ts: -------------------------------------------------------------------------------- 1 | export type GasPrice = { 2 | price: number; 3 | maxPriorityFeePerGas?: number; 4 | maxFeePerGas?: number; 5 | }; 6 | 7 | export type GasPriceEstimation = { 8 | pricePerGwei: number; 9 | standardPriceGwei: number; 10 | fastPriceGwei: number; 11 | rapidPriceGwei: number; 12 | }; 13 | 14 | export class GasPriceService { 15 | public async getLatest(): Promise { 16 | return null; 17 | } 18 | 19 | public async getGasPriceEstimation(): Promise { 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/services/util/snapshot.service.ts: -------------------------------------------------------------------------------- 1 | import { Contract } from '@ethersproject/contracts'; 2 | import { networkConfig } from '~/lib/config/network-config'; 3 | import { BaseProvider } from '@ethersproject/providers'; 4 | import DelegateRegistryAbi from '~/lib/abi/DelegateRegistry.json'; 5 | import { Address } from 'wagmi'; 6 | 7 | export class SnapshotService { 8 | constructor(private readonly contractAddress: string) {} 9 | 10 | public async getDelegation({ 11 | userAddress, 12 | provider, 13 | id, 14 | }: { 15 | userAddress: Address | undefined; 16 | provider: BaseProvider; 17 | id: string; 18 | }): Promise { 19 | const contract = new Contract(this.contractAddress, DelegateRegistryAbi, provider); 20 | const address = await contract.delegation(userAddress, id); 21 | return address; 22 | } 23 | } 24 | 25 | export const snapshotService = new SnapshotService(networkConfig.snapshot.contractAddress); 26 | -------------------------------------------------------------------------------- /lib/user/useUserAccount.ts: -------------------------------------------------------------------------------- 1 | import { useAccount } from 'wagmi'; 2 | import { useEffect } from 'react'; 3 | import { useBoolean } from '@chakra-ui/hooks'; 4 | import { makeVar } from '@apollo/client'; 5 | 6 | export const userAddressVar = makeVar(undefined); 7 | 8 | export function useUserAccount() { 9 | const query = useAccount(); 10 | const [isFirstRender, setFirstRender] = useBoolean(true); 11 | 12 | useEffect(() => { 13 | setFirstRender.off(); 14 | }, []); 15 | 16 | useEffect(() => { 17 | if (query.address !== userAddressVar()) { 18 | userAddressVar(query.address); 19 | } 20 | }, [query.address]); 21 | 22 | return { 23 | ...query, 24 | isLoading: query.isConnecting || isFirstRender, 25 | isConnecting: query.isConnecting || isFirstRender, 26 | userAddress: query.address?.toLowerCase(), 27 | isConnected: !!query.address && !isFirstRender, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /lib/user/useUserTokenBalances.tsx: -------------------------------------------------------------------------------- 1 | import { useGetTokens } from '~/lib/global/useToken'; 2 | import { useUserBalances } from '~/lib/user/useUserBalances'; 3 | import { createContext, ReactNode, useContext } from 'react'; 4 | 5 | export const UserTokenBalancesContext = createContext | null>(null); 6 | 7 | export function UserTokenBalancesProvider(props: { children: ReactNode }) { 8 | const { tokens } = useGetTokens(); 9 | const tokenAddresses = tokens.map((token) => token.address); 10 | 11 | const balances = useUserBalances(tokenAddresses); 12 | 13 | return {props.children}; 14 | } 15 | 16 | export const useUserTokenBalances = () => useContext(UserTokenBalancesContext) as ReturnType; 17 | -------------------------------------------------------------------------------- /lib/util/address.ts: -------------------------------------------------------------------------------- 1 | import { getAddress } from 'ethers/lib/utils'; 2 | import { networkConfig } from '~/lib/config/network-config'; 3 | 4 | export function addressesMatch(address1: string, address2: string) { 5 | return address1.toLowerCase() === address2.toLowerCase(); 6 | } 7 | 8 | export function addressShortDisplayName(address: string) { 9 | const formatted = getAddress(address); 10 | 11 | return `${formatted.slice(0, 4)}...${formatted.slice(-4)}`; 12 | } 13 | 14 | export function isVault(address: string) { 15 | return addressesMatch(address, networkConfig.balancer.vault); 16 | } 17 | 18 | export function isBatchRelayer(address: string) { 19 | return addressesMatch(address, networkConfig.balancer.batchRelayer); 20 | } 21 | -------------------------------------------------------------------------------- /lib/util/apr-util.ts: -------------------------------------------------------------------------------- 1 | import numeral from 'numeral'; 2 | import { GqlPoolAprValue } from '~/apollo/generated/graphql-codegen-generated'; 3 | 4 | const formatApr = (apr: string) => { 5 | if (parseFloat(apr) < 0.0000001) { 6 | return '0.00%'; 7 | } 8 | 9 | return numeral(apr).format('0.00%'); 10 | }; 11 | 12 | export function getApr(apr: GqlPoolAprValue): string { 13 | if (apr.__typename === 'GqlPoolAprRange') { 14 | return `${formatApr(apr.min)} - ${formatApr(apr.max)}`; 15 | } else { 16 | return formatApr(apr.total); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/util/etherscan.ts: -------------------------------------------------------------------------------- 1 | import { networkConfig } from '~/lib/config/network-config'; 2 | 3 | export function etherscanGetTokenUrl(tokenAddress: string): string { 4 | return `${networkConfig.etherscanUrl}/token/${tokenAddress}`; 5 | } 6 | 7 | export function etherscanGetAddressUrl(address: string): string { 8 | return `${networkConfig.etherscanUrl}/address/${address}`; 9 | } 10 | 11 | export function etherscanGetTxUrl(tx: string): string { 12 | return `${networkConfig.etherscanUrl}/tx/${tx}`; 13 | } 14 | 15 | export function etherscanGetBlockUrl(blockNumber: number): string { 16 | return `${networkConfig.etherscanUrl}/block/${blockNumber}`; 17 | } 18 | 19 | export function etherscanTxShortenForDisplay(txHash: string) { 20 | return txHash.slice(0, 12) + '...'; 21 | } 22 | 23 | export function etherscanGetContractWriteUrl(address: string): string { 24 | return `${networkConfig.etherscanUrl}/address/${address}#writeContract`; 25 | } 26 | 27 | export function etherscanGetContractReadUrl(address: string): string { 28 | return `${networkConfig.etherscanUrl}/address/${address}#readContract`; 29 | } 30 | -------------------------------------------------------------------------------- /lib/util/input-util.ts: -------------------------------------------------------------------------------- 1 | import { KeyboardEvent } from 'react'; 2 | 3 | export function tokenInputBlockInvalidCharacters(event: KeyboardEvent): void { 4 | ['e', 'E', '+', '-'].includes(event.key) && event.preventDefault(); 5 | } 6 | 7 | export function tokenInputTruncateDecimalPlaces(value: string, decimalPlaces: number): string { 8 | if (value.includes('.')) { 9 | const [leftDigits, rightDigits] = value.split('.'); 10 | 11 | if (rightDigits && rightDigits.length > decimalPlaces) { 12 | const maxLength = leftDigits.length + decimalPlaces + 1; 13 | 14 | return value.slice(0, maxLength); 15 | } 16 | } 17 | 18 | return value; 19 | } 20 | -------------------------------------------------------------------------------- /lib/util/transaction-util.ts: -------------------------------------------------------------------------------- 1 | export function transactionMessageFromError(error: Error): string { 2 | const unknown = error as any; 3 | 4 | if (unknown.reason) { 5 | const reason = unknown.reason as string; 6 | 7 | if (reason.indexOf('BAL#507') !== -1) { 8 | return 'Your transaction failed due to excessive slippage. You can increase your max slippage and try again. BAL#507'; 9 | } else if (reason.indexOf('BAL#506') !== -1) { 10 | return 'Your transaction failed due to excessive slippage. You can increase your max slippage and try again. BAL#506'; 11 | } else if (reason.indexOf('BAL#505') !== -1) { 12 | return 'Your transaction failed due to excessive slippage. You can increase your max slippage and try again. BAL#505'; 13 | } 14 | 15 | return `An error occurred: ${reason}`; 16 | } 17 | 18 | if (error.message.indexOf('Connector not found') !== -1) { 19 | return 'Unable to connect to your wallet. Please ensure your wallet is unlocked and available.'; 20 | } 21 | 22 | return `An error occurred: ${error.message}`; 23 | } 24 | -------------------------------------------------------------------------------- /lib/util/urls.ts: -------------------------------------------------------------------------------- 1 | export function getBaseUrl() { 2 | if (typeof window === 'undefined') { 3 | return 'http://localhost:3000'; 4 | } 5 | 6 | if (window.location.origin) { 7 | return window.location.origin; 8 | } 9 | 10 | const { protocol, hostname, port } = window.location; 11 | return `${protocol}//${hostname}${port ? ':' + port : ''}`; 12 | } 13 | -------------------------------------------------------------------------------- /lib/util/useApproveBatchRelayer.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction, vaultContractConfig } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import { useUserAccount } from '~/lib/user/useUserAccount'; 4 | 5 | export function useApproveBatchRelayer() { 6 | const networkConfig = useNetworkConfig(); 7 | const { userAddress } = useUserAccount(); 8 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 9 | config: { 10 | ...vaultContractConfig, 11 | functionName: 'setRelayerApproval', 12 | }, 13 | transactionType: 'APPROVE', 14 | }); 15 | 16 | function approve() { 17 | submit({ 18 | args: [userAddress, networkConfig.balancer.batchRelayer, true], 19 | toastText: `Approve Batch Relayer`, 20 | }); 21 | } 22 | 23 | return { 24 | approve, 25 | ...rest, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /lib/util/useApproveMinter.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import BalancerPseudoMinterAbi from '~/lib/abi/BalancerPseudoMinter.json'; 4 | 5 | export function useApproveMinter() { 6 | const networkConfig = useNetworkConfig(); 7 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 8 | config: { 9 | addressOrName: networkConfig.gauge.balancerPseudoMinterAddress, 10 | contractInterface: BalancerPseudoMinterAbi, 11 | functionName: 'setMinterApproval', 12 | }, 13 | transactionType: 'APPROVE', 14 | }); 15 | 16 | function approve() { 17 | submit({ 18 | args: [networkConfig.balancer.batchRelayer, true], 19 | toastText: `Approve batch relayer for minting`, 20 | }); 21 | } 22 | 23 | return { 24 | approve, 25 | ...rest, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /lib/util/useApproveToken.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import ERC20Abi from '../abi/ERC20.json'; 3 | import { MaxUint256 } from '@ethersproject/constants'; 4 | import { TokenBase } from '~/lib/services/token/token-types'; 5 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 6 | 7 | export function useApproveToken(token: TokenBase) { 8 | const networkConfig = useNetworkConfig(); 9 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 10 | config: { 11 | addressOrName: token.address || '', 12 | contractInterface: ERC20Abi, 13 | functionName: 'approve', 14 | }, 15 | transactionType: 'APPROVE', 16 | }); 17 | 18 | function approve(contractToApprove = networkConfig.balancer.vault) { 19 | submit({ 20 | args: [contractToApprove, MaxUint256.toString()], 21 | toastText: `Approve ${token.symbol}`, 22 | }); 23 | } 24 | 25 | return { 26 | approve, 27 | ...rest, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /lib/util/useHasBatchRelayerApproval.ts: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | import { useUserAccount } from '~/lib/user/useUserAccount'; 3 | import VaultAbi from '~/lib/abi/VaultAbi.json'; 4 | import { useMultiCall } from '~/lib/util/useMultiCall'; 5 | 6 | export function useHasBatchRelayerApproval() { 7 | const networkConfig = useNetworkConfig(); 8 | const { userAddress } = useUserAccount(); 9 | 10 | const { data, ...rest } = useMultiCall({ 11 | abi: VaultAbi, 12 | enabled: !!userAddress, 13 | calls: [ 14 | { 15 | address: networkConfig.balancer.vault, 16 | functionName: 'hasApprovedRelayer', 17 | args: [userAddress, networkConfig.balancer.batchRelayer], 18 | }, 19 | ], 20 | }); 21 | 22 | return { 23 | ...rest, 24 | data: (data ? data[0] : undefined) as boolean | undefined, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /lib/util/useHasMinterApproval.ts: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | import { useUserAccount } from '~/lib/user/useUserAccount'; 3 | import { useMultiCall } from '~/lib/util/useMultiCall'; 4 | import BalancerPseudoMinterAbi from '~/lib/abi/BalancerPseudoMinter.json'; 5 | 6 | export function useHasMinterApproval() { 7 | const networkConfig = useNetworkConfig(); 8 | const { userAddress } = useUserAccount(); 9 | 10 | const { data, ...rest } = useMultiCall({ 11 | abi: BalancerPseudoMinterAbi, 12 | enabled: !!userAddress && networkConfig.gaugeEnabled, 13 | calls: [ 14 | { 15 | address: networkConfig.gauge.balancerPseudoMinterAddress, 16 | functionName: 'getMinterApproval', 17 | args: [networkConfig.balancer.batchRelayer, userAddress], 18 | }, 19 | ], 20 | }); 21 | 22 | return { 23 | ...rest, 24 | data: (data ? data[0] : undefined) as boolean | undefined, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /lib/util/useUnwrapEth.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import WETHAbi from '../abi/WETH.json'; 3 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 4 | import { parseUnits } from 'ethers/lib/utils'; 5 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 6 | 7 | export function useUnwrapEth() { 8 | const networkConfig = useNetworkConfig(); 9 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 10 | config: { 11 | addressOrName: networkConfig.wethAddress, 12 | contractInterface: WETHAbi, 13 | functionName: 'withdraw', 14 | }, 15 | transactionType: 'UNWRAP', 16 | }); 17 | 18 | function unwrap(amount: AmountHumanReadable) { 19 | submit({ 20 | args: [parseUnits(amount, 18)], 21 | toastText: `Unwrapping ${amount} w${networkConfig.eth.symbol}`, 22 | }); 23 | } 24 | 25 | return { 26 | unwrap, 27 | ...rest, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /lib/util/useUserAllowances.ts: -------------------------------------------------------------------------------- 1 | import { useAllowances } from '~/lib/util/useAllowances'; 2 | import { TokenBase } from '~/lib/services/token/token-types'; 3 | import { useUserAccount } from '~/lib/user/useUserAccount'; 4 | 5 | export function useUserAllowances(tokens: (TokenBase | null)[], contractAddress?: string) { 6 | const { userAddress } = useUserAccount(); 7 | 8 | return useAllowances(userAddress || null, tokens, contractAddress); 9 | } 10 | -------------------------------------------------------------------------------- /lib/util/useWrapEth.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import WETHAbi from '../abi/WETH.json'; 3 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 4 | import { parseUnits } from 'ethers/lib/utils'; 5 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 6 | 7 | export function useWrapEth() { 8 | const networkConfig = useNetworkConfig(); 9 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 10 | config: { 11 | addressOrName: networkConfig.wethAddress, 12 | contractInterface: WETHAbi, 13 | functionName: 'deposit', 14 | }, 15 | transactionType: 'WRAP', 16 | }); 17 | 18 | function wrap(amount: AmountHumanReadable) { 19 | submit({ 20 | args: [], 21 | toastText: `Wrapping ${amount} ${networkConfig.eth.symbol}`, 22 | overrides: { 23 | value: parseUnits(amount, 18), 24 | }, 25 | }); 26 | } 27 | 28 | return { 29 | wrap, 30 | ...rest, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /lib/util/web3.ts: -------------------------------------------------------------------------------- 1 | import { GqlToken } from '~/apollo/generated/graphql-codegen-generated'; 2 | 3 | export async function addTokenToWallet(token: GqlToken | null) { 4 | const provider = window.ethereum as any; 5 | try { 6 | // wasAdded is a boolean. Like any RPC method, an error may be thrown. 7 | const wasAdded = await provider.request({ 8 | method: 'wallet_watchAsset', 9 | params: { 10 | type: 'ERC20', // Initially only supports ERC20, but eventually more! 11 | options: { 12 | address: token?.address, // The address that the token is at. 13 | symbol: token?.symbol, // A ticker symbol or shorthand, up to 5 chars. 14 | decimals: token?.decimals, // The number of decimals in the token 15 | image: token?.logoURI, // A string url of the token logo 16 | }, 17 | }, 18 | }); 19 | } catch (error) { 20 | console.log(error); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/wallet/useWalletConnectMetadata.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import { useUserAccount } from '../user/useUserAccount'; 3 | 4 | export function useWalletConnectMetadata() { 5 | const [walletName, setWalletName] = useState(''); 6 | const { connector } = useUserAccount(); 7 | 8 | useEffect(() => { 9 | if (!connector?.getProvider) return; 10 | if (connector.id !== 'walletConnect') return; 11 | connector.getProvider().then((provider) => { 12 | const walletConnectProvider = provider as any; 13 | try { 14 | setWalletName(walletConnectProvider.signer.session.peer.metadata.name); 15 | } catch { 16 | // Ignore errors in metadata 17 | } 18 | }); 19 | }, [connector]); 20 | 21 | const isSafeAccountViaWalletConnect = walletName === 'Safe{Wallet}'; 22 | 23 | return { isSafeAccountViaWalletConnect }; 24 | } 25 | -------------------------------------------------------------------------------- /modules/compose/AdvancedPoolComposeProgress.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import { ChevronDown } from 'react-feather'; 4 | import { useCompose } from './ComposeProvider'; 5 | 6 | interface Props { 7 | step: number; 8 | } 9 | 10 | export default function AdvancedPoolComposeProgress({ step }: Props) { 11 | const { progressValidatedTo } = useCompose(); 12 | 13 | const chevronColour = progressValidatedTo > step ? 'green.500' : 'red.500'; 14 | return ( 15 | 16 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /modules/compose/AdvancedPoolComposeSubmit.tsx: -------------------------------------------------------------------------------- 1 | import { Alert, Button, VStack } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import { useCompose } from './ComposeProvider'; 4 | import { sumBy } from 'lodash'; 5 | import { isAddress } from 'ethers/lib/utils.js'; 6 | 7 | interface Props {} 8 | 9 | export function AdvancedPoolComposeSubmit(props: Props) { 10 | const { setActiveStep, tokens, feeManager, isPoolNameValid, getPoolFeeValidations, getTokenAndWeightValidations } = 11 | useCompose(); 12 | 13 | const totalTokenWeight = sumBy(tokens, (token) => token.weight); 14 | const isInvalidTokenWeighTotal = totalTokenWeight < 100; 15 | const isInvalidFeeManager = feeManager === null || feeManager === '' || !isAddress(feeManager); 16 | const isPreviewDisabled = 17 | isInvalidTokenWeighTotal || 18 | isInvalidFeeManager || 19 | !getTokenAndWeightValidations().isValid || 20 | !getPoolFeeValidations().isValid || 21 | !isPoolNameValid(); 22 | function goToPreview() { 23 | // TODO validate inputs 24 | setActiveStep('preview'); 25 | } 26 | 27 | return ( 28 | 29 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /modules/compose/ComposeFlow.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useCompose } from './ComposeProvider'; 3 | import ComposeChooseFlowType from './ComposeChooseFlowType'; 4 | import AdvancedPoolCreation from './AdvancedPoolCreation'; 5 | import SimpleCreationChooseTokens from './SimpleCreationChooseTokens.tsx'; 6 | import PoolComposePreview from './PoolComposePreview'; 7 | 8 | interface Props {} 9 | 10 | export default function ComposeFlow(props: Props) { 11 | const { activeStep, creationExperience } = useCompose(); 12 | switch (creationExperience) { 13 | case 'simple': 14 | switch (activeStep) { 15 | case 'choose-tokens': 16 | return ; 17 | default: 18 | return ; 19 | } 20 | case 'advanced': 21 | switch (activeStep) { 22 | case 'preview': 23 | return ; 24 | default: 25 | return ; 26 | } 27 | default: 28 | return ; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /modules/compose/SimpleCreationChooseTokens.tsx.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Heading, Text, VStack } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import Card from '~/components/card/Card'; 4 | 5 | interface Props {} 6 | 7 | export default function SimpleCreationChooseTokens(props: Props) { 8 | return ( 9 | 10 | 11 | fds 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /modules/global/GlobalRenderer.tsx: -------------------------------------------------------------------------------- 1 | import { useUserAccount } from '~/lib/user/useUserAccount'; 2 | import { useGetAppGlobalPollingDataQuery, useGetUserDataQuery } from '~/apollo/generated/graphql-codegen-generated'; 3 | import { useEffectOnce } from '~/lib/util/custom-hooks'; 4 | import { useEffect, useRef } from 'react'; 5 | import { Box } from '@chakra-ui/react'; 6 | 7 | export function GlobalRenderer() { 8 | const currentUserAddress = useRef(''); 9 | const { isConnected, userAddress } = useUserAccount(); 10 | const { startPolling: startPollingAppData } = useGetAppGlobalPollingDataQuery({ fetchPolicy: 'network-only' }); 11 | const { startPolling: startPollingUserData, refetch: refetchUserData } = useGetUserDataQuery({ 12 | fetchPolicy: 'network-only', 13 | }); 14 | 15 | useEffectOnce(() => { 16 | startPollingAppData(60_000); 17 | }); 18 | 19 | useEffect(() => { 20 | if (userAddress) { 21 | startPollingUserData(30_000); 22 | } 23 | 24 | if (userAddress && userAddress !== currentUserAddress.current) { 25 | refetchUserData(); 26 | currentUserAddress.current = userAddress; 27 | } 28 | }, [isConnected, userAddress]); 29 | 30 | return {null}; 31 | } 32 | -------------------------------------------------------------------------------- /modules/migrate/BeetsMigrationButton.tsx: -------------------------------------------------------------------------------- 1 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 2 | import { BeetsSubmitTransactionButton } from '~/components/button/BeetsSubmitTransactionButton'; 3 | import { useMigrateBeets } from './lib/useMigrateBeets'; 4 | 5 | interface Props { 6 | amount: AmountHumanReadable; 7 | onConfirmed?: () => void; 8 | onPending?: () => void; 9 | onSubmitting?: () => void; 10 | onCanceled?: () => void; 11 | isDisabled?: boolean; 12 | size?: string; 13 | inline?: boolean; 14 | isLoading?: boolean; 15 | } 16 | 17 | export function BeetsMigrationButton({ amount, ...rest }: Props) { 18 | const { migrate, ...query } = useMigrateBeets(); 19 | 20 | return ( 21 | { 25 | migrate(amount); 26 | }} 27 | {...rest} 28 | > 29 | Migrate 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /modules/migrate/lib/useMigrateBeets.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import MultiBeetsMigrationAbi from '~/lib/abi/MultiBeetsMigration.json'; 3 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 4 | import { parseUnits } from 'ethers/lib/utils.js'; 5 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 6 | 7 | export function useMigrateBeets() { 8 | const networkConfig = useNetworkConfig(); 9 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 10 | config: { 11 | addressOrName: networkConfig.beets.migration, 12 | contractInterface: MultiBeetsMigrationAbi, 13 | functionName: 'exchange', 14 | }, 15 | transactionType: 'MIGRATE', 16 | }); 17 | 18 | function migrate(amount: AmountHumanReadable) { 19 | submit({ 20 | args: [parseUnits(amount, 18)], 21 | toastText: `Migrate ${amount} multiBEETS`, 22 | }); 23 | } 24 | 25 | return { 26 | migrate, 27 | ...rest, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /modules/nav/FooterLink.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Link, LinkProps } from '@chakra-ui/react'; 2 | import { ReactNode } from 'react'; 3 | import { NextLink } from '~/components/link/NextLink'; 4 | 5 | interface Props extends LinkProps { 6 | children: ReactNode | ReactNode[]; 7 | linkType?: 'internal' | 'external'; 8 | href: string; 9 | } 10 | 11 | export function FooterLink({ linkType = 'external', href, ...rest }: Props) { 12 | return ( 13 | 14 | {linkType === 'internal' ? ( 15 | 19 | {rest.children} 20 | 21 | ) : ( 22 | 30 | )} 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /modules/nav/NavbarLink.tsx: -------------------------------------------------------------------------------- 1 | import { Box, BoxProps, Text } from '@chakra-ui/react'; 2 | import Link from 'next/link'; 3 | 4 | interface Props extends Omit { 5 | selected?: boolean; 6 | href: string; 7 | text: string; 8 | } 9 | 10 | export function NavbarLink({ href, selected, text, ...rest }: Props) { 11 | return ( 12 | 13 | 14 | 20 | {text} 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /modules/nav/SubNavBarStat.tsx: -------------------------------------------------------------------------------- 1 | import { HStack, Skeleton, StackProps, Text } from '@chakra-ui/react'; 2 | 3 | import numeral from 'numeral'; 4 | 5 | interface Props extends StackProps { 6 | loading: boolean; 7 | value: string; 8 | label: string; 9 | } 10 | 11 | export function SubNavBarStat({ label, value, loading, ...rest }: Props) { 12 | return ( 13 | 14 | 15 | {label}: 16 | 17 | {loading ? ( 18 | 19 | ) : ( 20 | 21 | {numeral(value).format('$0.00a')} 22 | 23 | )} 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /modules/nav/lib/useGaugeClaimGetContractCallData.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query'; 2 | import { gaugeService } from '~/lib/services/staking/gauge.service'; 3 | import { Zero } from '@ethersproject/constants'; 4 | 5 | export function useGaugeClaimGetContractCallData( 6 | hasPendingNonBALRewards: boolean, 7 | hasPendingBalRewards: boolean, 8 | gauges: string[], 9 | ) { 10 | return useQuery( 11 | ['claimGetContractCallData', gauges], 12 | () => { 13 | const contractCallData = gaugeService.getGaugeClaimRewardsContractCallData({ 14 | hasPendingNonBALRewards, 15 | hasPendingBalRewards, 16 | gauges, 17 | outputReference: Zero, 18 | }); 19 | 20 | return contractCallData; 21 | }, 22 | { 23 | enabled: gauges && !!gauges.length && (hasPendingNonBALRewards || hasPendingBalRewards), 24 | staleTime: 0, 25 | cacheTime: 0, 26 | }, 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /modules/nav/lib/useUserGaugeClaimAllPendingRewards.ts: -------------------------------------------------------------------------------- 1 | import { batchRelayerContractConfig, useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | 3 | export function useUserGaugeClaimAllPendingRewards() { 4 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 5 | config: batchRelayerContractConfig, 6 | transactionType: 'HARVEST', 7 | }); 8 | 9 | function claimAll(contractCalls: string[]) { 10 | return submit({ 11 | args: [contractCalls], 12 | toastText: 'Claim all pool rewards', 13 | }); 14 | } 15 | 16 | return { 17 | claimAll, 18 | ...rest, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /modules/nav/lib/useUserHarvestAllPendingRewards.ts: -------------------------------------------------------------------------------- 1 | import { useMasterChefHarvestAllRewards } from '~/lib/global/useMasterChefHarvestAllRewards'; 2 | 3 | export function useUserHarvestAllPendingRewards() { 4 | const { harvestAll: masterChefHarvestAll, ...rest } = useMasterChefHarvestAllRewards(); 5 | 6 | function harvestAll(farmIds: string[]) { 7 | if (farmIds.length === 1 && farmIds[0] === '') return; 8 | masterChefHarvestAll(farmIds); 9 | } 10 | 11 | return { 12 | ...rest, 13 | harvestAll, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /modules/pool/detail/components/PoolDetailActions.tsx: -------------------------------------------------------------------------------- 1 | import { BeetsBox } from '~/components/box/BeetsBox'; 2 | import { BoxProps, Button, Flex } from '@chakra-ui/react'; 3 | 4 | import NextLink from 'next/link'; 5 | import { PoolDetailPossibleYieldText } from '~/modules/pool/detail/components/PoolDetailPossibleYieldText'; 6 | import { usePool } from '~/modules/pool/lib/usePool'; 7 | 8 | interface Props extends BoxProps {} 9 | 10 | export function PoolDetailActions({ ...rest }: Props) { 11 | const { pool, totalApr } = usePool(); 12 | 13 | return ( 14 | 15 | {totalApr > 0.05 ? : null} 16 | 0.05 ? 10 : 4}> 17 | 18 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /modules/pool/detail/components/PoolHeaderStaking.tsx: -------------------------------------------------------------------------------- 1 | import { networkConfig } from '~/lib/config/network-config'; 2 | import { PoolHeaderStakingAura } from './thirdparty/PoolHeaderStakingAura'; 3 | import { PoolHeaderStakingFmoney } from './thirdparty/PoolHeaderStakingFmoney'; 4 | import { PoolHeaderStakingMerkl } from './thirdparty/PoolHeaderStakingMerkl'; 5 | 6 | export function PoolHeaderStaking({ poolId }: { poolId: string }) { 7 | const name = networkConfig.thirdPartyStakingPools.find((pool) => pool.poolId === poolId)?.name; 8 | 9 | switch (name) { 10 | case 'aura': 11 | return ; 12 | case 'merkl': 13 | return ; 14 | case 'fmoney': 15 | return ; 16 | default: 17 | return null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /modules/pool/detail/components/charts/chart-util.ts: -------------------------------------------------------------------------------- 1 | export function chartGetPrimaryColor(chainId: string, opacity: number) { 2 | if (chainId === '10') { 3 | return `rgba(119, 119, 119, ${opacity})`; 4 | } 5 | 6 | return `rgba(88, 95, 198, ${opacity})`; 7 | } 8 | 9 | export function chartGetSecondaryColor(chainId: string, opacity: number) { 10 | if (chainId === '10') { 11 | return `rgba(0, 255, 255, ${opacity})`; 12 | } 13 | 14 | return `rgba(143, 147, 214, ${opacity})`; 15 | } 16 | -------------------------------------------------------------------------------- /modules/pool/detail/components/thirdparty/PoolHeaderPoints.tsx: -------------------------------------------------------------------------------- 1 | import { Text } from '@chakra-ui/react'; 2 | import { CustomTooltip } from '~/components/tooltip/CustomTooltip'; 3 | 4 | export function PoolHeaderPoints({ textString }: { textString: string }) { 5 | return ( 6 | 9 | {textString} 10 | 11 | } 12 | content={'Liquidity providers in this pool also earn partner points'} 13 | border="2px" 14 | borderColor="beets.green" 15 | bg="whiteAlpha.300" 16 | /> 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /modules/pool/detail/components/thirdparty/PoolHeaderStakingAura.tsx: -------------------------------------------------------------------------------- 1 | import { Link, HStack, Text } from '@chakra-ui/react'; 2 | import { CustomTooltip } from '~/components/tooltip/CustomTooltip'; 3 | import { networkConfig } from '~/lib/config/network-config'; 4 | import Image from 'next/image'; 5 | import AuraLogo from '~/assets/logo/aura_iso_colors.png'; 6 | 7 | export function PoolHeaderStakingAura({ poolId }: { poolId: string }) { 8 | const url = networkConfig.thirdPartyStakingPools.find((pool) => pool.poolId === poolId)?.url; 9 | 10 | return ( 11 | 14 | 15 | 16 | Boosted rewards available on Aura 17 | 18 | Aura Finance 19 | 20 | 21 | } 22 | content={'For this pool you can deposit & stake your BPT on Aura Finance for extra boosted rewards'} 23 | border="2px" 24 | borderColor="aura.pink" 25 | _hover={{ borderColor: 'aura.purple' }} 26 | bg="whiteAlpha.300" 27 | /> 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /modules/pool/detail/components/thirdparty/PoolHeaderStakingFmoney.tsx: -------------------------------------------------------------------------------- 1 | import { Link, HStack, Text } from '@chakra-ui/react'; 2 | import { CustomTooltip } from '~/components/tooltip/CustomTooltip'; 3 | import { networkConfig } from '~/lib/config/network-config'; 4 | import Image from 'next/image'; 5 | import FmoneyLogo from '~/assets/logo/fmoney-pfp.png'; 6 | 7 | export function PoolHeaderStakingFmoney({ poolId }: { poolId: string }) { 8 | const url = networkConfig.thirdPartyStakingPools.find((pool) => pool.poolId === poolId)?.url; 9 | 10 | return ( 11 | 14 | 15 | 16 | Rewards available on fMoney Markets 17 | 18 | fMoney Markets 19 | 20 | 21 | } 22 | content={'For this pool you can deposit & stake your BPT on fMoney Markets for rewards'} 23 | border="2px" 24 | borderColor="fmoney.green.100" 25 | _hover={{ borderColor: 'fmoney.green.400' }} 26 | bg="whiteAlpha.300" 27 | /> 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /modules/pool/detail/components/thirdparty/PoolHeaderStakingMerkl.tsx: -------------------------------------------------------------------------------- 1 | import { Link, HStack, Text } from '@chakra-ui/react'; 2 | import { CustomTooltip } from '~/components/tooltip/CustomTooltip'; 3 | import { networkConfig } from '~/lib/config/network-config'; 4 | import Image from 'next/image'; 5 | import MerklLogo from '~/assets/logo/merkl2x.png'; 6 | 7 | export function PoolHeaderStakingMerkl({ poolId }: { poolId: string }) { 8 | const url = networkConfig.thirdPartyStakingPools.find((pool) => pool.poolId === poolId)?.url; 9 | 10 | return ( 11 | 14 | 15 | 16 | Earn rewards on Merkl 17 | 18 | Merkl 19 | 20 | 21 | } 22 | content={'For this pool you can earn rewards on Merkl'} 23 | border="2px" 24 | borderColor="merkl.melrose" 25 | _hover={{ borderColor: 'white' }} 26 | bg="whiteAlpha.300" 27 | /> 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /modules/pool/detail/components/warning/PoolDetailWarning.tsx: -------------------------------------------------------------------------------- 1 | import { Box, HStack, Link } from '@chakra-ui/react'; 2 | import { ToastType, useToast } from '~/components/toast/BeetsToast'; 3 | import { useEffect } from 'react'; 4 | import { PoolDetailWarning as PoolDetailWarningType } from '~/lib/config/network-config-type'; 5 | 6 | interface Props { 7 | warning: PoolDetailWarningType; 8 | } 9 | 10 | export function PoolDetailWarning({ warning }: Props) { 11 | const { showToast } = useToast(); 12 | 13 | useEffect(() => { 14 | showToast({ 15 | id: 'pool-detail-alert', 16 | type: ToastType.Warn, 17 | content: ( 18 | 19 | 20 | {warning.message}{' '} 21 | {warning.link && ( 22 | 23 | {warning.link.text} 24 | 25 | )} 26 | 27 | 28 | ), 29 | }); 30 | }, []); 31 | 32 | return null; 33 | } 34 | -------------------------------------------------------------------------------- /modules/pool/detail/components/warning/PoolOvernightWarning.tsx: -------------------------------------------------------------------------------- 1 | import { Box, HStack, Link } from '@chakra-ui/react'; 2 | import { usePool } from '~/modules/pool/lib/usePool'; 3 | import { ToastType, useToast } from '~/components/toast/BeetsToast'; 4 | import { useEffect } from 'react'; 5 | 6 | export function PoolOvernightWarning() { 7 | const { showToast } = useToast(); 8 | const { pool } = usePool(); 9 | 10 | useEffect(() => { 11 | if (pool.id === '0xb1c9ac57594e9b1ec0f3787d9f6744ef4cb0a02400000000000000000000006e') { 12 | showToast({ 13 | id: 'pool-detail-alert', 14 | type: ToastType.Info, 15 | content: ( 16 | 17 | 18 | This pool is boosted by Overnight. When investing in this pool, the majority of your assets 19 | are wrapped in wUSD+ and wDAI+. Understand how Overnight generates yield prior to investing 20 | in this pool. Website:{' '} 21 | 22 | overnight.fi 23 | 24 | 25 | 26 | ), 27 | }); 28 | } 29 | }, []); 30 | 31 | return null; 32 | } 33 | -------------------------------------------------------------------------------- /modules/pool/invest/components/PoolInvestPreview.tsx: -------------------------------------------------------------------------------- 1 | import { Box, StackDivider, VStack } from '@chakra-ui/react'; 2 | import { BeetsBox } from '~/components/box/BeetsBox'; 3 | import { useInvest } from '~/modules/pool/invest/lib/useInvest'; 4 | import { PoolInvestSummary } from '~/modules/pool/invest/components/PoolInvestSummary'; 5 | import { PoolInvestActions } from '~/modules/pool/invest/components/PoolInvestActions'; 6 | import TokenRow from '~/components/token/TokenRow'; 7 | import React from 'react'; 8 | 9 | interface Props { 10 | onInvestComplete(): void; 11 | onClose(): void; 12 | } 13 | 14 | export function PoolInvestPreview({ onInvestComplete, onClose }: Props) { 15 | const { selectedInvestTokensWithAmounts } = useInvest(); 16 | 17 | return ( 18 | 19 | 20 | 21 | 22 | } mt="4" p="2"> 23 | {selectedInvestTokensWithAmounts.map((token) => { 24 | return ; 25 | })} 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /modules/pool/invest/components/PoolInvestPriceImpact.tsx: -------------------------------------------------------------------------------- 1 | import { HStack, Skeleton, Text, VStack } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import { usePoolJoinGetBptOutAndPriceImpactForTokensIn } from '~/modules/pool/invest/lib/usePoolJoinGetBptOutAndPriceImpactForTokensIn'; 4 | 5 | export function PoolInvestPriceImpact() { 6 | const { formattedPriceImpact, hasHighPriceImpact, hasMediumPriceImpact, isLoading } = 7 | usePoolJoinGetBptOutAndPriceImpactForTokensIn(); 8 | 9 | return ( 10 | 11 | 12 | 13 | Price impact 14 | 15 | {isLoading ? ( 16 | 17 | ) : ( 18 | 22 | {formattedPriceImpact} 23 | 24 | )} 25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /modules/pool/invest/components/PoolInvestStablePoolDescription.tsx: -------------------------------------------------------------------------------- 1 | import { Highlight } from '@chakra-ui/react'; 2 | 3 | export function PoolInvestStablePoolDescription() { 4 | return ( 5 | <> 6 | 7 | Stable pools allow you to invest with custom asset ratios without encountering significant price impact. 8 | 9 |
10 |
11 | 12 | Deposits that move the token balances closer to equal ratios will receive a small bonus, while deposits 13 | that move the ratios further apart will incur a small penalty. 14 | 15 |
16 |
17 | 18 | 19 | In instances where one asset in the pool loses its peg, it's possible to incur severe impermanent 20 | loss. 21 | 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /modules/pool/invest/components/PoolInvestWeightedPoolDescription.tsx: -------------------------------------------------------------------------------- 1 | import { Highlight } from '@chakra-ui/react'; 2 | 3 | export function PoolInvestWeightedPoolDescription() { 4 | return ( 5 | <> 6 | 10 | Investing proportionally into this pool ensures you will not be subject to the fees associated with 11 | price impact. 12 | 13 |
14 |
15 | 19 | Alternatively, you can customize your investment and deposit in this pool with any tokens in your 20 | wallet. However, investing in this manner may shift the pool out of balance and is therefore subject to 21 | price impact. 22 | 23 |
24 |
25 | When investing in any liquidity pool, you will receive pool tokens (BPT) which represent your share of the 26 | pool. 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /modules/pool/lib/usePoolGaugeClaimRewardsGetContractCallData.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query'; 2 | import { usePool } from '~/modules/pool/lib/usePool'; 3 | import { gaugeService } from '~/lib/services/staking/gauge.service'; 4 | import { usePoolUserPendingRewards } from './usePoolUserPendingRewards'; 5 | import { Zero } from '@ethersproject/constants'; 6 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 7 | 8 | export function usePoolGaugeClaimRewardsGetContractCallData() { 9 | const { pool } = usePool(); 10 | const { hasPendingBalRewards, hasPendingNonBALRewards } = usePoolUserPendingRewards(); 11 | const networkConfig = useNetworkConfig(); 12 | 13 | const data = { 14 | hasPendingNonBALRewards, 15 | hasPendingBalRewards, 16 | outputReference: Zero, 17 | gauges: [pool.staking?.gauge?.id || ''], 18 | }; 19 | 20 | return useQuery( 21 | ['unstakeGetContractCallData', data], 22 | () => { 23 | const contractCallData = gaugeService.getGaugeClaimRewardsContractCallData(data); 24 | return contractCallData; 25 | }, 26 | { enabled: networkConfig.gaugeEnabled }, 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /modules/pool/lib/usePoolWithOnChainData.tsx: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query'; 2 | import { useProvider } from 'wagmi'; 3 | import { GqlPoolUnion } from '~/apollo/generated/graphql-codegen-generated'; 4 | import { useGetTokens } from '~/lib/global/useToken'; 5 | import { poolOnChainBalanceService } from '~/lib/services/pool/pool-on-chain-balance.service'; 6 | 7 | export function usePoolWithOnChainData(pool: GqlPoolUnion) { 8 | const provider = useProvider(); 9 | const { priceFor } = useGetTokens(); 10 | 11 | const tokenPrices = pool.tokens.map((token) => ({ address: token.address, price: priceFor(token.address) })); 12 | 13 | return useQuery(['usePoolWithOnChainData', pool.id, tokenPrices], async () => { 14 | return poolOnChainBalanceService.updatePoolWithOnChainBalanceData({ pool, provider, tokenPrices }); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /modules/pool/stake/lib/useGaugeCheckpoint.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import BeethovenCheckpointer from '~/lib/abi/BeethovenCheckpointer.json'; 4 | 5 | export function useGaugeCheckpoint() { 6 | const networkConfig = useNetworkConfig(); 7 | 8 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 9 | config: { 10 | addressOrName: networkConfig.gauge.checkpointHelper, 11 | contractInterface: BeethovenCheckpointer, 12 | functionName: 'checkpoint_my_gauges', 13 | }, 14 | transactionType: 'CHECKPOINT', 15 | }); 16 | 17 | function checkpoint(gauges: string[]) { 18 | return submit({ 19 | args: [gauges], 20 | toastText: `Checkpoint my gauges`, 21 | walletText: `Checkpoint gauges to receive maximum boost`, 22 | }); 23 | } 24 | 25 | return { 26 | checkpoint, 27 | ...rest, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /modules/pool/stake/lib/useGaugeStakingMigration.ts: -------------------------------------------------------------------------------- 1 | import { batchRelayerContractConfig, useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | 3 | export function useStakingMigration() { 4 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 5 | config: batchRelayerContractConfig, 6 | transactionType: 'MIGRATE', 7 | }); 8 | 9 | async function migrateGaugeStakedBalance(calls: string[]) { 10 | submit({ 11 | args: [calls], 12 | toastText: 'Migrating staked balance...', 13 | walletText: 'Migrate staked balance.', 14 | }); 15 | } 16 | 17 | return { 18 | migrateGaugeStakedBalance, 19 | ...rest, 20 | }; 21 | } -------------------------------------------------------------------------------- /modules/pool/stake/lib/usePoolUserStakingAllowance.ts: -------------------------------------------------------------------------------- 1 | import { useUserAllowances } from '~/lib/util/useUserAllowances'; 2 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 3 | import { usePool } from '~/modules/pool/lib/usePool'; 4 | 5 | export function usePoolUserStakingAllowance() { 6 | const { pool } = usePool(); 7 | 8 | const { hasApprovalForAmount, ...rest } = useUserAllowances([pool], pool.staking?.address || ''); 9 | 10 | function hasApprovalToStakeAmount(amount: AmountHumanReadable) { 11 | return hasApprovalForAmount(pool.address, amount); 12 | } 13 | 14 | return { 15 | ...rest, 16 | hasApprovalToStakeAmount, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /modules/pool/withdraw/components/PoolWithdrawStablePoolDescription.tsx: -------------------------------------------------------------------------------- 1 | import { Highlight } from '@chakra-ui/react'; 2 | 3 | export function PoolWithdrawStablePoolDescription() { 4 | return ( 5 | <> 6 | 7 | Due to the unique design of stable pools, you can withdraw into a single token without encountering 8 | significant price impact. 9 | 10 |
11 |
12 | 13 | Withdraws that move the token balances closer to equal ratios will receive a small bonus, while 14 | withdraws that move the ratios further apart will incur a small penalty. 15 | 16 |
17 |
18 | When withdrawing from any liquidity pool, your BPT tokens are exchanged for the underlying pool assets. 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /modules/pool/withdraw/components/PoolWithdrawWeightedPoolDescription.tsx: -------------------------------------------------------------------------------- 1 | import { Highlight } from '@chakra-ui/react'; 2 | 3 | export function PoolWithdrawWeightedPoolDescription() { 4 | return ( 5 | <> 6 | 10 | Withdrawing proportionally from this pool ensures you will not be subject to the potential fees caused 11 | by price impact. 12 | 13 |
14 |
15 | 16 | Alternatively, you can withdraw a single asset. This is similar to swapping all other assets for the 17 | selected asset, and is therefore subject to the fees associated with price impact. 18 | 19 |
20 |
21 | When withdrawing from any liquidity pool, your BPT tokens are exchanged for the underlying pool assets. 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /modules/pool/withdraw/lib/usePoolExitGetProportionalWithdrawEstimate.ts: -------------------------------------------------------------------------------- 1 | import { useReactiveVar } from '@apollo/client'; 2 | import { withdrawStateVar } from '~/modules/pool/withdraw/lib/useWithdrawState'; 3 | import { useQuery } from 'react-query'; 4 | import { oldBnumScaleAmount, oldBnumToHumanReadable } from '~/lib/services/pool/lib/old-big-number'; 5 | import { usePoolUserBptBalance } from '~/modules/pool/lib/usePoolUserBptBalance'; 6 | import { useWithdraw } from '~/modules/pool/withdraw/lib/useWithdraw'; 7 | import { usePool } from '~/modules/pool/lib/usePool'; 8 | 9 | export function usePoolExitGetProportionalWithdrawEstimate() { 10 | const { poolService, pool } = usePool(); 11 | const { userWalletBptBalance } = usePoolUserBptBalance(); 12 | const { proportionalPercent } = useReactiveVar(withdrawStateVar); 13 | const bptIn = oldBnumToHumanReadable(oldBnumScaleAmount(userWalletBptBalance).times(proportionalPercent / 100)); 14 | const { selectedWithdrawTokenAddresses } = useWithdraw(); 15 | 16 | return useQuery( 17 | ['exitGetProportionalWithdrawEstimate', pool.id, bptIn, selectedWithdrawTokenAddresses], 18 | async () => { 19 | const result = await poolService.exitGetProportionalWithdrawEstimate(bptIn, selectedWithdrawTokenAddresses); 20 | 21 | return result; 22 | }, 23 | {}, 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /modules/pool/withdraw/lib/usePoolExitGetSingleAssetWithdrawForBptIn.ts: -------------------------------------------------------------------------------- 1 | import { useReactiveVar } from '@apollo/client'; 2 | import { withdrawStateVar } from '~/modules/pool/withdraw/lib/useWithdrawState'; 3 | import { useQuery } from 'react-query'; 4 | import { usePoolUserBptBalance } from '~/modules/pool/lib/usePoolUserBptBalance'; 5 | import { usePool } from '~/modules/pool/lib/usePool'; 6 | 7 | export function usePoolExitGetSingleAssetWithdrawForBptIn() { 8 | const { poolService } = usePool(); 9 | const { singleAsset } = useReactiveVar(withdrawStateVar); 10 | const { userWalletBptBalance } = usePoolUserBptBalance(); 11 | 12 | return useQuery( 13 | ['exitGetSingleAssetWithdrawForBptIn', userWalletBptBalance, singleAsset?.address], 14 | async () => { 15 | if (!singleAsset) { 16 | return { 17 | tokenAmount: '0', 18 | priceImpact: 0, 19 | }; 20 | } 21 | 22 | return poolService.exitGetSingleAssetWithdrawForBptIn(userWalletBptBalance, singleAsset.address); 23 | }, 24 | { enabled: !!singleAsset }, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /modules/pool/withdraw/lib/useWithdraw.ts: -------------------------------------------------------------------------------- 1 | import { GqlPoolToken } from '~/apollo/generated/graphql-codegen-generated'; 2 | import { useWithdrawState } from '~/modules/pool/withdraw/lib/useWithdrawState'; 3 | import { usePool } from '~/modules/pool/lib/usePool'; 4 | import { sumBy } from 'lodash'; 5 | import { useGetTokens } from '~/lib/global/useToken'; 6 | 7 | export function useWithdraw() { 8 | const { pool } = usePool(); 9 | const { selectedOptions, proportionalAmounts } = useWithdrawState(); 10 | 11 | const selectedWithdrawTokens: GqlPoolToken[] = pool.withdrawConfig.options.map((option) => 12 | selectedOptions[`${option.poolTokenIndex}`] 13 | ? option.tokenOptions.find( 14 | (tokenOption) => tokenOption.address === selectedOptions[`${option.poolTokenIndex}`], 15 | )! 16 | : option.tokenOptions[0], 17 | ); 18 | 19 | const selectedWithdrawTokenAddresses = selectedWithdrawTokens.map((token) => token.address); 20 | 21 | return { 22 | selectedWithdrawTokens, 23 | selectedWithdrawTokenAddresses, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /modules/pools/components/PoolListItemStaking.tsx: -------------------------------------------------------------------------------- 1 | import { networkConfig } from '~/lib/config/network-config'; 2 | import { PoolListItemStakingAura } from './thirdparty/PoolListItemStakingAura'; 3 | import { PoolListItemStakingFmoney } from './thirdparty/PoolListItemStakingFmoney'; 4 | import { PoolListItemStakingMerkl } from './thirdparty/PoolListItemStakingMerkl'; 5 | 6 | export function PoolListItemStaking({ poolId }: { poolId: string }) { 7 | const name = networkConfig.thirdPartyStakingPools.find((pool) => pool.poolId === poolId)?.name; 8 | 9 | switch (name) { 10 | case 'aura': 11 | return ; 12 | case 'merkl': 13 | return ; 14 | case 'fmoney': 15 | return ; 16 | default: 17 | return null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /modules/pools/components/PoolListItemWarning.tsx: -------------------------------------------------------------------------------- 1 | import { AlertTriangle } from 'react-feather'; 2 | import { Box, BoxProps } from '@chakra-ui/react'; 3 | import BeetsTooltip from '~/components/tooltip/BeetsTooltip'; 4 | 5 | interface Props extends BoxProps { 6 | message: string; 7 | } 8 | 9 | export function PoolListItemWarning({ message, ...rest }: Props) { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /modules/pools/components/PoolListSortLink.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, ButtonProps, Text, Button } from '@chakra-ui/react'; 2 | import { ArrowUp, ArrowDown } from 'react-feather'; 3 | import { GqlPoolOrderDirection } from '~/apollo/generated/graphql-codegen-generated'; 4 | 5 | interface Props extends ButtonProps { 6 | title: string; 7 | orderDirection?: GqlPoolOrderDirection | null; 8 | } 9 | 10 | export default function PoolListSortLink({ title, orderDirection, ...rest }: Props) { 11 | return ( 12 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /modules/pools/components/PoolListTop.tsx: -------------------------------------------------------------------------------- 1 | import { Box, HStack } from '@chakra-ui/react'; 2 | import { PoolListTabs } from '~/modules/pools/components/PoolListTabs'; 3 | import { PoolListSearch } from '~/modules/pools/components/PoolListSearch'; 4 | 5 | export function PoolListTop() { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /modules/pools/components/thirdparty/PoolListItemPoints.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import BeetsTooltip from '~/components/tooltip/BeetsTooltip'; 3 | import Image from 'next/image'; 4 | import PointsIcon from '~/assets/icons/points.svg'; 5 | 6 | export function PoolListItemPoints() { 7 | return ( 8 | 9 | 10 | Points 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /modules/pools/components/thirdparty/PoolListItemStakingAura.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import BeetsTooltip from '~/components/tooltip/BeetsTooltip'; 3 | import Image from 'next/image'; 4 | import AuraLogo from '~/assets/logo/aura_iso_colors.png'; 5 | 6 | export function PoolListItemStakingAura() { 7 | return ( 8 | 12 | 13 | Aura Finance 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /modules/pools/components/thirdparty/PoolListItemStakingFmoney.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import BeetsTooltip from '~/components/tooltip/BeetsTooltip'; 3 | import Image from 'next/image'; 4 | import FmoneyLogo from '~/assets/logo/fmoney-pfp.png'; 5 | 6 | export function PoolListItemStakingFmoney() { 7 | return ( 8 | 9 | 10 | fMoney Markets 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /modules/pools/components/thirdparty/PoolListItemStakingMerkl.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import BeetsTooltip from '~/components/tooltip/BeetsTooltip'; 3 | import Image from 'next/image'; 4 | import MerklLogo from '~/assets/logo/merkl2x.png'; 5 | 6 | export function PoolListItemStakingMerkl() { 7 | return ( 8 | 9 | 10 | Merkl 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /modules/recovery-exit/lib/useGetRecoveryPoolTokens.ts: -------------------------------------------------------------------------------- 1 | import { useMultiCall } from '~/lib/util/useMultiCall'; 2 | import VaultAbi from '../../../lib/abi/Vault.json'; 3 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 4 | import { BigNumber } from 'ethers'; 5 | 6 | export function useGetRecoveryPoolTokens(poolIds: string[]) { 7 | const networkConfig = useNetworkConfig(); 8 | 9 | const multicall = useMultiCall<[string[], BigNumber[]]>({ 10 | abi: VaultAbi, 11 | calls: poolIds.map((poolId) => ({ 12 | address: networkConfig.balancer.vault, 13 | functionName: 'getPoolTokens', 14 | args: [poolId], 15 | })), 16 | enabled: poolIds.length > 0, 17 | }); 18 | 19 | const poolTokens = multicall.data 20 | ? poolIds.map((poolId, index) => { 21 | const data = multicall.data[index]; 22 | 23 | return { 24 | poolId, 25 | tokens: data ? data[0] : [], 26 | balances: data ? data[1] : [], 27 | }; 28 | }) 29 | : []; 30 | 31 | return { 32 | ...multicall, 33 | poolTokens, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /modules/reliquary/components/RelicMaturityModal.tsx: -------------------------------------------------------------------------------- 1 | import { Modal, ModalCloseButton, ModalOverlay } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import { BeetsModalContent } from '~/components/modal/BeetsModal'; 4 | import RelicMaturity from './charts/RelicMaturity'; 5 | 6 | interface Props { 7 | isOpen: boolean; 8 | onClose: () => void; 9 | } 10 | 11 | export default function RelicMaturityModal({ isOpen, onClose }: Props) { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /modules/reliquary/components/ReliquaryBatchRelayerApprovalButton.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import { BeetsSubmitTransactionButton } from '~/components/button/BeetsSubmitTransactionButton'; 3 | import { useBatchRelayerRelicApprove } from '../lib/useBatchRelayerRelicApprove'; 4 | 5 | interface Props { 6 | contractToApprove?: string; 7 | onConfirmed?: () => void; 8 | onPending?: () => void; 9 | onSubmitting?: () => void; 10 | onCanceled?: () => void; 11 | isDisabled?: boolean; 12 | size?: string; 13 | buttonText?: string; 14 | } 15 | 16 | export function ReliquaryBatchRelayerApprovalButton({ buttonText, ...rest }: Props) { 17 | const { approveAll, approve, ...query } = useBatchRelayerRelicApprove(true); 18 | 19 | return ( 20 | 21 | approveAll(true)} 25 | {...rest} 26 | borderColor="beets.green" 27 | _focus={{ boxShadow: 'none' }} 28 | submittingText="Confirm..." 29 | pendingText="Waiting..." 30 | > 31 | {buttonText ? buttonText : 'Approve Batch Relayer for all Relics'} 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /modules/reliquary/components/ReliquaryConnectWallet.tsx: -------------------------------------------------------------------------------- 1 | import { Heading, Text, VStack } from '@chakra-ui/react'; 2 | import { motion } from 'framer-motion'; 3 | import React from 'react'; 4 | import { WalletConnectButton } from '~/components/button/WalletConnectButton'; 5 | 6 | interface Props {} 7 | 8 | export default function ReliquaryConnectWallet(props: Props) { 9 | return ( 10 | 21 | 22 | Get started by connecting your wallet 23 | 24 | 25 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /modules/reliquary/components/stats/ReliquaryGlobalStats.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Grid, GridItem } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import { ReliquaryCurveChart } from '../charts/ReliquaryCurveChart'; 4 | import { ReliquaryDetailsCharts } from '../charts/ReliquaryDetailsCharts'; 5 | import ReliquaryOverallStats from './ReliquaryOverallStats'; 6 | 7 | export default function ReliquaryGlobalStats() { 8 | return ( 9 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /modules/reliquary/components/unused/ReliquaryCard.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Card from '~/components/card/Card'; 3 | 4 | interface Props { 5 | 6 | } 7 | 8 | export default function ReliquaryCard(props: Props) { 9 | 10 | return ( 11 | 12 | lmao 13 | 14 | ) 15 | } -------------------------------------------------------------------------------- /modules/reliquary/components/unused/ReliquaryMigrateDemoButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@chakra-ui/react'; 2 | import { useReliquaryFbeetsMigrateContractCallData } from '~/modules/reliquary/lib/useReliquaryFbeetsMigrateContractCallData'; 3 | import { useReliquaryZap } from '~/modules/reliquary/lib/useReliquaryZap'; 4 | 5 | export function ReliquaryMigrateDemoButton() { 6 | // const { data: contractCalls, fbeetsBalance } = useReliquaryFbeetsMigrateContractCallData(); 7 | // const { reliquaryZap } = useReliquaryZap('MIGRATE'); 8 | 9 | // return ( 10 | // 17 | // ); 18 | return null; 19 | } 20 | -------------------------------------------------------------------------------- /modules/reliquary/components/unused/ReliquaryMyStats.tsx: -------------------------------------------------------------------------------- 1 | import { Grid, GridItem } from '@chakra-ui/react'; 2 | import React from 'react'; 3 | import RelicMaturity from '../charts/RelicMaturity'; 4 | import RelicApr from './RelicApr'; 5 | import RelicLiquidity from './RelicLiquidity'; 6 | import RelicRewards from './RelicRewards'; 7 | 8 | export default function ReliquaryMyStats() { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useAllRelicsWithdrawAndHarvestContractCallData.tsx: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query'; 2 | import { useSlippage } from '~/lib/global/useSlippage'; 3 | import { reliquaryZapService } from '~/lib/services/staking/reliquary-zap.service'; 4 | import { useUserAccount } from '~/lib/user/useUserAccount'; 5 | import { useAllRelicsDepositBalances } from './useAllRelicsDepositBalances'; 6 | 7 | export function useAllRelicsWithdrawAndHarvestContractCallData() { 8 | const { userAddress } = useUserAccount(); 9 | const { slippage } = useSlippage(); 10 | const { relics, allRelicsBeetsAmount, allRelicsWftmAmount, alllRelicsBptTotal } = useAllRelicsDepositBalances(); 11 | 12 | return useQuery( 13 | ['useAllRelicsWithdrawAndHarvestContractCallData', userAddress, slippage, relics.map((relic) => relic.relicId)], 14 | async () => { 15 | return reliquaryZapService.getReliquaryWithdrawManyAndHarvestContractCallData({ 16 | userAddress: userAddress || '', 17 | relics, 18 | slippage, 19 | totalBptAmount: alllRelicsBptTotal, 20 | totalWftmAmount: allRelicsWftmAmount, 21 | totalBeetsAmount: allRelicsBeetsAmount, 22 | }); 23 | }, 24 | { enabled: !!userAddress }, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useBatchRelayerHasApprovedForAll.ts: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | import { useMultiCall } from '~/lib/util/useMultiCall'; 3 | import ReliquaryAbi from '~/lib/abi/Reliquary.json'; 4 | import { useUserAccount } from '~/lib/user/useUserAccount'; 5 | 6 | export function useBatchRelayerHasApprovedForAll() { 7 | const networkConfig = useNetworkConfig(); 8 | const { userAddress } = useUserAccount(); 9 | 10 | const { data, ...rest } = useMultiCall({ 11 | abi: ReliquaryAbi, 12 | enabled: true, 13 | calls: [ 14 | { 15 | address: networkConfig.reliquary.address, 16 | functionName: 'isApprovedForAll', 17 | args: [userAddress, networkConfig.balancer.batchRelayer], 18 | }, 19 | ], 20 | }); 21 | 22 | return { 23 | ...rest, 24 | data: (data ? data[0] : undefined) as boolean | undefined, 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useBatchRelayerHasRelicApproval.ts: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | import { useMultiCall } from '~/lib/util/useMultiCall'; 3 | import ReliquaryAbi from '~/lib/abi/Reliquary.json'; 4 | import { isSameAddress } from '@balancer-labs/sdk'; 5 | 6 | export function useBatchRelayerHasRelicApproval(relicId?: number) { 7 | const networkConfig = useNetworkConfig(); 8 | 9 | const { data, ...rest } = useMultiCall({ 10 | abi: ReliquaryAbi, 11 | enabled: typeof relicId === 'number', 12 | calls: [ 13 | { 14 | address: networkConfig.reliquary.address, 15 | functionName: 'getApproved', 16 | args: [relicId], 17 | }, 18 | ], 19 | }); 20 | 21 | return { 22 | ...rest, 23 | data: (data ? isSameAddress(data[0] as string, networkConfig.balancer.batchRelayer) : undefined) as 24 | | boolean 25 | | undefined, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useBatchRelayerRelicApprove.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import ReliquaryAbi from '~/lib/abi/Reliquary.json'; 4 | 5 | export function useBatchRelayerRelicApprove(useApproveAll = false) { 6 | const networkConfig = useNetworkConfig(); 7 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 8 | config: { 9 | addressOrName: networkConfig.reliquary.address, 10 | contractInterface: ReliquaryAbi, 11 | functionName: useApproveAll ? 'setApprovalForAll' : 'approve', 12 | }, 13 | transactionType: 'APPROVE', 14 | }); 15 | 16 | function approve(relicId: number) { 17 | submit({ 18 | args: [networkConfig.balancer.batchRelayer, relicId], 19 | toastText: `Approve relic #${relicId}`, 20 | }); 21 | } 22 | 23 | function approveAll(approve: boolean) { 24 | submit({ 25 | args: [networkConfig.balancer.batchRelayer, approve], 26 | toastText: 'Approve all current and future relics', 27 | }); 28 | } 29 | 30 | return { 31 | approve, 32 | approveAll, 33 | ...rest, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useDelegateClear.tsx: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import DelegateRegistryAbi from '~/lib/abi/DelegateRegistry.json'; 4 | 5 | export function useDelegateClear() { 6 | const networkConfig = useNetworkConfig(); 7 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 8 | config: { 9 | addressOrName: networkConfig.snapshot.contractAddress, 10 | contractInterface: DelegateRegistryAbi, 11 | functionName: 'clearDelegate', 12 | }, 13 | transactionType: 'UNDELEGATE', 14 | }); 15 | 16 | function clearDelegate() { 17 | submit({ 18 | args: [networkConfig.snapshot.id], 19 | toastText: 'Undelegate to MDs', 20 | }); 21 | } 22 | 23 | return { 24 | clearDelegate, 25 | ...rest, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useDelegateSet.tsx: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import DelegateRegistryAbi from '~/lib/abi/DelegateRegistry.json'; 4 | 5 | export function useDelegateSet() { 6 | const networkConfig = useNetworkConfig(); 7 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 8 | config: { 9 | addressOrName: networkConfig.snapshot.contractAddress, 10 | contractInterface: DelegateRegistryAbi, 11 | functionName: 'setDelegate', 12 | }, 13 | transactionType: 'DELEGATE', 14 | }); 15 | 16 | function setDelegate() { 17 | submit({ 18 | args: [networkConfig.snapshot.id, networkConfig.snapshot.delegateAddress], 19 | toastText: 'Delegate to MDs', 20 | }); 21 | } 22 | 23 | return { 24 | setDelegate, 25 | ...rest, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useDelegation.tsx: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | import { useQuery } from 'react-query'; 3 | import { snapshotService } from '~/lib/services/util/snapshot.service'; 4 | import { useUserAccount } from '~/lib/user/useUserAccount'; 5 | import { Address, useProvider } from 'wagmi'; 6 | 7 | export function useDelegation() { 8 | const { userAddress } = useUserAccount(); 9 | const provider = useProvider(); 10 | const networkConfig = useNetworkConfig(); 11 | 12 | return useQuery( 13 | ['getDelegation', userAddress], 14 | async (): Promise => { 15 | const delegationAddress = await snapshotService.getDelegation({ 16 | userAddress: userAddress as Address, 17 | provider, 18 | id: networkConfig.snapshot.id, 19 | }); 20 | return delegationAddress === networkConfig.snapshot.delegateAddress; 21 | }, 22 | { enabled: !!userAddress }, 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useRelicBurn.tsx: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import ReliquaryAbi from '~/lib/abi/Reliquary.json'; 4 | 5 | export function useRelicBurn() { 6 | const networkConfig = useNetworkConfig(); 7 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 8 | config: { 9 | addressOrName: networkConfig.reliquary.address, 10 | contractInterface: ReliquaryAbi, 11 | functionName: 'burn', 12 | }, 13 | transactionType: 'BURN', 14 | }); 15 | 16 | function burn(relicId: string) { 17 | submit({ 18 | args: [parseInt(relicId, 10)], 19 | toastText: `Burn relic #${relicId}`, 20 | }); 21 | } 22 | 23 | return { 24 | burn, 25 | ...rest, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useRelicHarvestRewards.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | import ReliquaryAbi from '~/lib/abi/Reliquary.json'; 4 | import { useUserAccount } from '~/lib/user/useUserAccount'; 5 | import useReliquary from '~/modules/reliquary/lib/useReliquary'; 6 | 7 | export function useRelicHarvestRewards() { 8 | const networkConfig = useNetworkConfig(); 9 | const { userAddress } = useUserAccount(); 10 | const { selectedRelicId } = useReliquary(); 11 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 12 | config: { 13 | addressOrName: networkConfig.reliquary.address, 14 | contractInterface: ReliquaryAbi, 15 | functionName: 'harvest', 16 | }, 17 | transactionType: 'HARVEST', 18 | }); 19 | 20 | function harvest() { 21 | submit({ 22 | args: [selectedRelicId, userAddress], 23 | toastText: `Harvesting rewards for relic #${selectedRelicId}`, 24 | walletText: `Harvest rewards for relic #${selectedRelicId}`, 25 | }); 26 | } 27 | 28 | return { 29 | harvest, 30 | ...rest, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useRelicPendingRewards.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query'; 2 | import useReliquary from '~/modules/reliquary/lib/useReliquary'; 3 | import { reliquaryService } from '~/lib/services/staking/reliquary.service'; 4 | import { useProvider } from 'wagmi'; 5 | 6 | export function useRelicPendingRewards() { 7 | const { selectedRelic } = useReliquary(); 8 | const provider = useProvider(); 9 | 10 | return useQuery( 11 | ['relicPendingRewards', selectedRelic?.relicId], 12 | async () => { 13 | return reliquaryService.getPendingRewardsForRelic({ 14 | relicId: selectedRelic?.relicId || '0', 15 | provider, 16 | }); 17 | }, 18 | { enabled: !!selectedRelic }, 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryCurrentStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export interface CurrentStepContextType { 4 | updateCurrentStep: (id: string) => void; 5 | currentStep: string | null; 6 | } 7 | 8 | export const CurrentStepContext = React.createContext(null); 9 | 10 | export function _useCurrentStep() { 11 | const [currentStep, setCurrentStep] = React.useState(null); 12 | 13 | const updateCurrentStep = (id: string) => { 14 | setCurrentStep(id); 15 | }; 16 | 17 | return { 18 | currentStep, 19 | updateCurrentStep, 20 | }; 21 | } 22 | 23 | export function CurrentStepProvider(props: { children: React.ReactNode }) { 24 | const steps = _useCurrentStep(); 25 | return {props.children}; 26 | } 27 | 28 | export const useCurrentStep = () => React.useContext(CurrentStepContext) as ReturnType; 29 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryDepositImpact.ts: -------------------------------------------------------------------------------- 1 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 2 | 3 | import { useQuery } from 'react-query'; 4 | import { ReliquaryService } from '~/lib/services/staking/reliquary.service'; 5 | import { useRef } from 'react'; 6 | import { useProvider } from 'wagmi'; 7 | 8 | export function useReliquaryDepositImpact(amount: number, relicId?: string) { 9 | const networkConfig = useNetworkConfig(); 10 | const provider = useProvider(); 11 | const reliquaryService = useRef( 12 | new ReliquaryService(networkConfig.reliquary.address, networkConfig.chainId, networkConfig.beets.address), 13 | ).current; 14 | const depositImpactQuery = useQuery( 15 | 'relicDepositImpact', 16 | async () => { 17 | if (Number.isNaN(amount) || !relicId) { 18 | return; 19 | } 20 | return await reliquaryService.getDepositImpact({ 21 | relicId, 22 | provider, 23 | amount, 24 | }); 25 | }, 26 | { 27 | enabled: !!relicId && !Number.isNaN(amount), 28 | }, 29 | ); 30 | 31 | return depositImpactQuery; 32 | } 33 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryGlobalStats.ts: -------------------------------------------------------------------------------- 1 | import { useGetReliquaryFarmSnapshotsQuery } from '~/apollo/generated/graphql-codegen-generated'; 2 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 3 | 4 | export function useReliquaryGlobalStats() { 5 | const config = useNetworkConfig(); 6 | const { data, ...rest } = useGetReliquaryFarmSnapshotsQuery({ 7 | variables: { id: `${config.reliquary.fbeets.farmId}`, range: 'THIRTY_DAYS' }, 8 | }); 9 | 10 | const latest = data && data.snapshots.length > 0 ? data.snapshots[data.snapshots.length - 1] : null; 11 | 12 | return { 13 | ...rest, 14 | data: latest, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryHarvestAllContractCallData.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query'; 2 | import { reliquaryZapService } from '~/lib/services/staking/reliquary-zap.service'; 3 | import { useUserAccount } from '~/lib/user/useUserAccount'; 4 | 5 | export function useReliquaryHarvestAllContractCallData(relicIds: number[]) { 6 | const { userAddress } = useUserAccount(); 7 | 8 | return useQuery( 9 | ['reliquaryHarvestAllContractCallData', relicIds, userAddress], 10 | async () => { 11 | return reliquaryZapService.getReliquaryHarvestAllContractCallData({ 12 | relicIds, 13 | recipient: userAddress || '', 14 | }); 15 | }, 16 | { enabled: !!userAddress && relicIds.length !== 0 }, 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryHarvestAllRewards.ts: -------------------------------------------------------------------------------- 1 | import { batchRelayerContractConfig, useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | 3 | export function useReliquaryHarvestAllRewards() { 4 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 5 | config: batchRelayerContractConfig, 6 | transactionType: 'HARVEST', 7 | }); 8 | 9 | function harvestAll(calls: string[]) { 10 | submit({ 11 | args: [calls], 12 | toastText: 'Harvesting all pending relic rewards', 13 | walletText: 'Harvest all pending relic rewards', 14 | }); 15 | } 16 | 17 | return { 18 | harvestAll, 19 | ...rest, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryLevelUp.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import { MaxUint256 } from '@ethersproject/constants'; 3 | import { TokenBase } from '~/lib/services/token/token-types'; 4 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 5 | import ReliquaryAbi from '~/lib/abi/Reliquary.json'; 6 | 7 | export function useReliquaryLevelUp() { 8 | const networkConfig = useNetworkConfig(); 9 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 10 | config: { 11 | addressOrName: networkConfig.reliquary.address, 12 | contractInterface: ReliquaryAbi, 13 | functionName: 'updatePosition', 14 | }, 15 | transactionType: 'LEVEL_UP', 16 | }); 17 | 18 | function levelUp(relicId: string) { 19 | submit({ 20 | args: [parseInt(relicId, 10)], 21 | toastText: `Level Up relic #${relicId}`, 22 | }); 23 | } 24 | 25 | return { 26 | levelUp, 27 | ...rest, 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryPendingRewards.ts: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query'; 2 | import { reliquaryService } from '~/lib/services/staking/reliquary.service'; 3 | import { useProvider } from 'wagmi'; 4 | import { useUserAccount } from '~/lib/user/useUserAccount'; 5 | import { networkConfig } from '~/lib/config/network-config'; 6 | 7 | export function useReliquaryPendingRewards() { 8 | const provider = useProvider(); 9 | const { userAddress } = useUserAccount(); 10 | 11 | return useQuery( 12 | ['reliquaryPendingRewards', networkConfig.reliquary.fbeets.farmId, userAddress], 13 | async () => { 14 | return reliquaryService.getPendingRewards({ 15 | farmIds: [networkConfig.reliquary.fbeets.farmId.toString()], 16 | userAddress: userAddress || '', 17 | provider, 18 | }); 19 | }, 20 | { enabled: !!userAddress && !!networkConfig.fbeets.address }, 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /modules/reliquary/lib/useReliquaryZap.ts: -------------------------------------------------------------------------------- 1 | import { batchRelayerContractConfig, useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | 3 | export function useReliquaryZap(type: 'MIGRATE' | 'DEPOSIT' | 'WITHDRAW') { 4 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 5 | config: batchRelayerContractConfig, 6 | transactionType: type === 'WITHDRAW' ? 'EXIT' : 'JOIN', 7 | }); 8 | 9 | async function reliquaryZap(calls: string[]) { 10 | submit({ 11 | args: [calls], 12 | toastText: 13 | type === 'WITHDRAW' 14 | ? 'Withdrawing from maBEETS' 15 | : type === 'MIGRATE' 16 | ? 'Migrating into maBEETS' 17 | : 'Depositing into maBEETS', 18 | walletText: 19 | type === 'WITHDRAW' 20 | ? 'Withdraw from maBEETS' 21 | : type === 'MIGRATE' 22 | ? 'Migrate into maBEETS' 23 | : 'Deposit into maBEETS', 24 | }); 25 | } 26 | 27 | return { 28 | reliquaryZap, 29 | ...rest, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /modules/reliquary/migrate/components/ReliquarySonicMigrateBridgeFtm.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Heading, Text, Link, Flex } from '@chakra-ui/react'; 2 | import { ExternalLink } from 'react-feather'; 3 | 4 | export function ReliquarySonicMigrateBridgeFtm() { 5 | return ( 6 | 7 | 4. Upgrade your FTM to S 8 | Use the Sonic native bridge to upgrade your FTM to S: 9 | 10 | 11 | https://my.soniclabs.com/upgrade 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /modules/reliquary/migrate/components/ReliquarySonicMigrateNextSteps.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Heading, Text, Link, Flex } from '@chakra-ui/react'; 2 | import { ExternalLink } from 'react-feather'; 3 | 4 | export function ReliquarySonicMigrateNextSteps() { 5 | return ( 6 | 7 | 6. Next steps 8 | Once you've completed the steps above, you can create your maBEETS relic on Sonic. 9 | 10 | 11 | https://ma.beets.fi/ 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /modules/reliquary/migrate/components/ReliquarySonicMigrateStakeS.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Heading, Text, Link, Flex } from '@chakra-ui/react'; 2 | import { ExternalLink } from 'react-feather'; 3 | 4 | export function ReliquarySonicMigrateStakeS() { 5 | return ( 6 | 7 | 5. Stake S for stS 8 | Stake your S to receive stS, Sonic's liquid staking token. 9 | 10 | 11 | https://beets.fi/stake 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /modules/reliquary/reliquary.gql: -------------------------------------------------------------------------------- 1 | query GetReliquaryFarmSnapshots($id: String!, $range: GqlPoolSnapshotDataRange!) { 2 | snapshots: beetsPoolGetReliquaryFarmSnapshots(id: $id, range: $range) { 3 | id 4 | farmId 5 | timestamp 6 | totalBalance 7 | totalLiquidity 8 | levelBalances { 9 | id 10 | level 11 | balance 12 | } 13 | relicCount 14 | totalBalance 15 | userCount 16 | tokenBalances { 17 | id 18 | address 19 | balance 20 | symbol 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /modules/reliquary/withdraw/components/ReliquaryWithdrawDescription.tsx: -------------------------------------------------------------------------------- 1 | import { Highlight } from '@chakra-ui/react'; 2 | 3 | export function ReliquaryWithdrawDescription() { 4 | return ( 5 | <> 6 | 10 | Withdrawing proportionally from this relic ensures you will not be subject to the potential fees caused 11 | by price impact. 12 | 13 |
14 |
15 | 16 | For now withdrawing a single asset is not available. This will be implemented at a later date. 17 | 18 |
19 |
20 | When withdrawing from any relic, your fBEETS are exchanged for the underlying tokens. 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /modules/reliquary/withdraw/lib/useReliquaryExitGetProportionalWithdrawEstimate.ts: -------------------------------------------------------------------------------- 1 | import { useReactiveVar } from '@apollo/client'; 2 | import { withdrawStateVar } from '~/modules/reliquary/withdraw/lib/useReliquaryWithdrawState'; 3 | import { useQuery } from 'react-query'; 4 | import { oldBnumScaleAmount, oldBnumToHumanReadable } from '~/lib/services/pool/lib/old-big-number'; 5 | import { useReliquaryWithdraw } from '~/modules/reliquary/withdraw/lib/useReliquaryWithdraw'; 6 | import { usePool } from '~/modules/pool/lib/usePool'; 7 | import useReliquary from '~/modules/reliquary/lib/useReliquary'; 8 | 9 | export function useReliquaryExitGetProportionalWithdrawEstimate() { 10 | const { poolService, pool } = usePool(); 11 | const { proportionalPercent } = useReactiveVar(withdrawStateVar); 12 | const { selectedRelic } = useReliquary(); 13 | const bptIn = oldBnumToHumanReadable( 14 | oldBnumScaleAmount(selectedRelic?.amount || '').times(proportionalPercent / 100), 15 | ); 16 | const { selectedWithdrawTokenAddresses } = useReliquaryWithdraw(); 17 | 18 | return useQuery( 19 | ['exitGetProportionalWithdrawEstimate', pool.id, bptIn, selectedWithdrawTokenAddresses], 20 | async () => { 21 | const result = await poolService.exitGetProportionalWithdrawEstimate(bptIn, selectedWithdrawTokenAddresses); 22 | 23 | return result; 24 | }, 25 | {}, 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /modules/reliquary/withdraw/lib/useReliquaryExitGetSingleAssetWithdrawForBptIn.ts: -------------------------------------------------------------------------------- 1 | import { useReactiveVar } from '@apollo/client'; 2 | import { withdrawStateVar } from '~/modules/reliquary/withdraw/lib/useReliquaryWithdrawState'; 3 | import { useQuery } from 'react-query'; 4 | import { usePoolUserBptBalance } from '~/modules/pool/lib/usePoolUserBptBalance'; 5 | import { usePool } from '~/modules/pool/lib/usePool'; 6 | 7 | export function useReliquaryExitGetSingleAssetWithdrawForBptIn() { 8 | const { poolService } = usePool(); 9 | const { singleAsset } = useReactiveVar(withdrawStateVar); 10 | const { userWalletBptBalance } = usePoolUserBptBalance(); 11 | 12 | return useQuery( 13 | ['exitGetSingleAssetWithdrawForBptIn', userWalletBptBalance, singleAsset?.address], 14 | async () => { 15 | if (!singleAsset) { 16 | return { 17 | tokenAmount: '0', 18 | priceImpact: 0, 19 | }; 20 | } 21 | 22 | return poolService.exitGetSingleAssetWithdrawForBptIn(userWalletBptBalance, singleAsset.address); 23 | }, 24 | { enabled: !!singleAsset }, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /modules/reliquary/withdraw/lib/useReliquaryWithdraw.ts: -------------------------------------------------------------------------------- 1 | import { GqlPoolToken } from '~/apollo/generated/graphql-codegen-generated'; 2 | import { useReliquaryWithdrawState } from '~/modules/reliquary/withdraw/lib/useReliquaryWithdrawState'; 3 | import { usePool } from '~/modules/pool/lib/usePool'; 4 | 5 | export function useReliquaryWithdraw() { 6 | const { pool } = usePool(); 7 | const { selectedOptions } = useReliquaryWithdrawState(); 8 | 9 | const selectedWithdrawTokens: GqlPoolToken[] = pool.withdrawConfig.options.map((option) => 10 | selectedOptions[`${option.poolTokenIndex}`] 11 | ? option.tokenOptions.find( 12 | (tokenOption) => tokenOption.address === selectedOptions[`${option.poolTokenIndex}`], 13 | )! 14 | : option.tokenOptions[0], 15 | ); 16 | 17 | const selectedWithdrawTokenAddresses = selectedWithdrawTokens.map((token) => token.address); 18 | 19 | return { 20 | selectedWithdrawTokens, 21 | selectedWithdrawTokenAddresses, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /modules/sftmx/components/stats/SftmxStatsFtmValidator.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import Card from '~/components/card/Card'; 3 | import { useSftmxGetStakingData } from '../../lib/useSftmxGetStakingData'; 4 | import { SftmxChartsFtmValidator } from '../charts/SftmxChartsFtmValidator'; 5 | import { groupBy, sortBy, sumBy } from 'lodash'; 6 | 7 | export function SftmxStatsFtmValidator() { 8 | const { data } = useSftmxGetStakingData(); 9 | const validatorsGroupedAndSummed = groupBy(data?.sftmxGetStakingData.vaults, 'validatorId'); 10 | const totalFtmAmounts = Object.keys(validatorsGroupedAndSummed).map((key) => ({ 11 | name: key, 12 | value: sumBy(validatorsGroupedAndSummed[key].map((value) => parseFloat(value.ftmAmountStaked))), 13 | validatorAddress: validatorsGroupedAndSummed[key][0].validatorAddress.toLowerCase(), 14 | })); 15 | 16 | const totalFtmAmountsSorted = sortBy(totalFtmAmounts, 'value').reverse(); 17 | 18 | return ( 19 | 20 | 21 | {data && } 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /modules/sftmx/components/tabs/stake/SftmxStakeButton.tsx: -------------------------------------------------------------------------------- 1 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 2 | import { BeetsSubmitTransactionButton } from '~/components/button/BeetsSubmitTransactionButton'; 3 | import { useSftmxStake } from '../../../lib/useSftmxStake'; 4 | 5 | interface Props { 6 | amount: AmountHumanReadable; 7 | onConfirmed?: () => void; 8 | onPending?: () => void; 9 | onSubmitting?: () => void; 10 | onCanceled?: () => void; 11 | isDisabled?: boolean; 12 | size?: string; 13 | inline?: boolean; 14 | isLoading?: boolean; 15 | } 16 | 17 | export function SftmxStakeButton({ amount, ...rest }: Props) { 18 | const { stake, ...query } = useSftmxStake(); 19 | 20 | return ( 21 | { 25 | stake(amount); 26 | }} 27 | {...rest} 28 | > 29 | Stake 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /modules/sftmx/components/tabs/withdraw/SftmxWithdrawButton.tsx: -------------------------------------------------------------------------------- 1 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 2 | import { BeetsSubmitTransactionButton } from '~/components/button/BeetsSubmitTransactionButton'; 3 | import { useSftmxWithdraw } from '../../../lib/useSftmxWithdraw'; 4 | 5 | interface Props { 6 | amount: AmountHumanReadable; 7 | wrId: string; 8 | onConfirmed?: () => void; 9 | onPending?: () => void; 10 | onSubmitting?: () => void; 11 | onCanceled?: () => void; 12 | isDisabled?: boolean; 13 | size?: string; 14 | inline?: boolean; 15 | isLoading?: boolean; 16 | isWithdrawn: boolean; 17 | } 18 | 19 | export function SftmxWithdrawButton({ amount, wrId, isWithdrawn, ...rest }: Props) { 20 | const { withdraw, ...query } = useSftmxWithdraw(); 21 | 22 | return ( 23 | { 27 | withdraw(amount, wrId); 28 | }} 29 | {...rest} 30 | > 31 | {isWithdrawn ? 'Withdrawn' : 'Withdraw'} 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /modules/sftmx/components/tabs/withdraw/SftmxWithdrawalRequestsHeader.tsx: -------------------------------------------------------------------------------- 1 | import { Text } from '@chakra-ui/layout'; 2 | import { Grid, GridItem } from '@chakra-ui/react'; 3 | 4 | export default function SftmxWithdrawalRequestsHeader() { 5 | return ( 6 | 17 | 18 | 19 | Amount 20 | 21 | 22 | 23 | 24 | Withdraw on 25 | 26 | 27 | {/* no header for third column */} 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxGetAllWithdrawalRequests.ts: -------------------------------------------------------------------------------- 1 | import { useProvider } from 'wagmi'; 2 | import { useQuery } from 'react-query'; 3 | import { sftmxService } from '~/lib/services/staking/sftmx.service'; 4 | import { BigNumber } from 'ethers'; 5 | 6 | export function useSftmxGetAllWithdrawalRequests(wrId: string) { 7 | const provider = useProvider(); 8 | 9 | return useQuery( 10 | ['sftmxGetAllWithdrawalRequests', wrId], 11 | async (): Promise<{ 12 | requestTime: BigNumber; 13 | poolAmount: BigNumber; 14 | undelegateAmount: BigNumber; 15 | penalty: BigNumber; 16 | user: string; 17 | isWithdrawn: boolean; 18 | }> => sftmxService.getAllWithdrawalRequests({ wrId, provider }), 19 | { enabled: !!wrId }, 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxGetCalculatePenalty.ts: -------------------------------------------------------------------------------- 1 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 2 | import { useProvider } from 'wagmi'; 3 | import { useQuery } from 'react-query'; 4 | import { BigNumber } from 'ethers'; 5 | import { sftmxService } from '~/lib/services/staking/sftmx.service'; 6 | 7 | export function useSftmxGetCalculatePenalty(amount: AmountHumanReadable) { 8 | const provider = useProvider(); 9 | 10 | return useQuery( 11 | ['sftmxGetCalculatePenalty', amount], 12 | async (): Promise<{ 13 | amountFtmReceived: BigNumber; 14 | amountUndelegated: BigNumber; 15 | amountPenalty: BigNumber; 16 | }> => sftmxService.getCalculatePenalty({ amount, provider }), 17 | { enabled: !!amount && amount !== '0' }, 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxGetFtmxAmountForFtm.ts: -------------------------------------------------------------------------------- 1 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 2 | import { useProvider } from 'wagmi'; 3 | import { useQuery } from 'react-query'; 4 | import { BigNumber } from 'ethers'; 5 | import { sftmxService } from '~/lib/services/staking/sftmx.service'; 6 | 7 | export function useSftmxGetFtmxAmountForFtm(amount: AmountHumanReadable) { 8 | const provider = useProvider(); 9 | 10 | return useQuery( 11 | ['sftmxGetFtmxAmountForFtm', amount], 12 | async (): Promise<{ amountSftmx: BigNumber }> => sftmxService.getFtmxAmountForFtm({ amount, provider }), 13 | { enabled: !!amount && amount !== '0' }, 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxGetStakingData.ts: -------------------------------------------------------------------------------- 1 | import { useSftmxGetStakingDataQuery } from '~/apollo/generated/graphql-codegen-generated'; 2 | 3 | export function useSftmxGetStakingData() { 4 | const { data, ...rest } = useSftmxGetStakingDataQuery(); 5 | 6 | return { 7 | ...rest, 8 | data, 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxGetWithdrawalRequests.ts: -------------------------------------------------------------------------------- 1 | import { useSftmxGetWithdrawalRequestsQuery } from '~/apollo/generated/graphql-codegen-generated'; 2 | import { useUserAccount } from '~/lib/user/useUserAccount'; 3 | import { AddressZero } from '@ethersproject/constants'; 4 | 5 | export function useSftmxGetWithdrawalRequests() { 6 | const { userAddress } = useUserAccount(); 7 | 8 | const { data, ...rest } = useSftmxGetWithdrawalRequestsQuery({ 9 | variables: { user: (userAddress || AddressZero) as string }, 10 | }); 11 | 12 | return { data, ...rest }; 13 | } 14 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxStake.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import FTMStakingAbi from '~/lib/abi/FTMStaking.json'; 3 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 4 | import { parseUnits } from 'ethers/lib/utils.js'; 5 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 6 | 7 | export function useSftmxStake() { 8 | const networkConfig = useNetworkConfig(); 9 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 10 | config: { 11 | addressOrName: networkConfig.sftmx.ftmStakingProxyAddress, 12 | contractInterface: FTMStakingAbi, 13 | functionName: 'deposit', 14 | }, 15 | transactionType: 'STAKE', 16 | }); 17 | 18 | function stake(amount: AmountHumanReadable) { 19 | submit({ 20 | args: [], 21 | overrides: { 22 | value: parseUnits(amount, 18), 23 | }, 24 | toastText: `Stake ${amount} FTM`, 25 | }); 26 | } 27 | 28 | return { 29 | stake, 30 | ...rest, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxUnstake.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import FTMStakingAbi from '~/lib/abi/FTMStaking.json'; 3 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 4 | import { parseUnits } from 'ethers/lib/utils.js'; 5 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 6 | import { BigNumber } from 'ethers'; 7 | 8 | export function useSftmxUnstake() { 9 | const networkConfig = useNetworkConfig(); 10 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 11 | config: { 12 | addressOrName: networkConfig.sftmx.ftmStakingProxyAddress, 13 | contractInterface: FTMStakingAbi, 14 | functionName: 'undelegate', 15 | }, 16 | transactionType: 'UNSTAKE', 17 | }); 18 | 19 | const wrID = `${Date.now()}`; 20 | 21 | function undelegate(amount: AmountHumanReadable, penalty: BigNumber) { 22 | submit({ 23 | args: [wrID, parseUnits(amount, 18), penalty], 24 | toastText: `Unstake ${amount} FTM`, 25 | }); 26 | } 27 | 28 | return { 29 | undelegate, 30 | ...rest, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /modules/sftmx/lib/useSftmxWithdraw.ts: -------------------------------------------------------------------------------- 1 | import { useSubmitTransaction } from '~/lib/util/useSubmitTransaction'; 2 | import FTMStakingAbi from '~/lib/abi/FTMStaking.json'; 3 | import { AmountHumanReadable } from '~/lib/services/token/token-types'; 4 | import { useNetworkConfig } from '~/lib/global/useNetworkConfig'; 5 | 6 | export function useSftmxWithdraw() { 7 | const networkConfig = useNetworkConfig(); 8 | const { submit, submitAsync, ...rest } = useSubmitTransaction({ 9 | config: { 10 | addressOrName: networkConfig.sftmx.ftmStakingProxyAddress, 11 | contractInterface: FTMStakingAbi, 12 | functionName: 'withdraw', 13 | }, 14 | transactionType: 'EXIT', 15 | }); 16 | 17 | function withdraw(amount: AmountHumanReadable, wrId: string) { 18 | submit({ 19 | args: [wrId, 0], 20 | toastText: `Withdraw ${amount} sFTMx`, 21 | }); 22 | } 23 | 24 | return { 25 | withdraw, 26 | ...rest, 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /modules/sftmx/sftmx.gql: -------------------------------------------------------------------------------- 1 | query SftmxGetStakingData { 2 | sftmxGetStakingData { 3 | exchangeRate 4 | maintenancePaused 5 | maxDepositLimit 6 | minDepositLimit 7 | numberOfVaults 8 | stakingApr 9 | totalFtmAmount 10 | totalFtmAmountInPool 11 | totalFtmAmountStaked 12 | undelegatePaused 13 | withdrawPaused 14 | withdrawalDelay 15 | numberOfVaults 16 | vaults { 17 | ftmAmountStaked 18 | isMatured 19 | unlockTimestamp 20 | validatorAddress 21 | validatorId 22 | vaultAddress 23 | vaultIndex 24 | } 25 | } 26 | } 27 | 28 | query SftmxGetWithdrawalRequests($user: String!) { 29 | sftmxGetWithdrawalRequests(user: $user) { 30 | amountSftmx 31 | id 32 | isWithdrawn 33 | requestTimestamp 34 | user 35 | } 36 | } 37 | 38 | query SftmxGetStakingSnapshots($range: GqlSftmxStakingSnapshotDataRange!) { 39 | snapshots: sftmxGetStakingSnapshots(range: $range) { 40 | exchangeRate 41 | id 42 | timestamp 43 | totalFtmAmount 44 | totalFtmAmountInPool 45 | totalFtmAmountStaked 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | // This file sets a custom webpack configuration to use your Next.js app 2 | // with Sentry. 3 | // https://nextjs.org/docs/api-reference/next.config.js/introduction 4 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ 5 | const { withSentryConfig } = require('@sentry/nextjs'); 6 | 7 | /** @type {import('next').NextConfig} */ 8 | const path = require('path'); 9 | const transpiled = require('next-transpile-modules')(['echarts', 'zrender']); 10 | 11 | const nextConfig = { 12 | reactStrictMode: true, 13 | productionBrowserSourceMaps: true, 14 | 15 | webpack(config) { 16 | config.resolve.alias['~'] = path.join(__dirname, 'src'); 17 | return config; 18 | }, 19 | 20 | sentry: { hideSourcemaps: true, autoInstrumentServerFunctions: false }, 21 | 22 | async redirects() { 23 | return [ 24 | { 25 | source: '/', 26 | destination: '/pools', 27 | permanent: false, 28 | }, 29 | { 30 | source: '/discord', 31 | destination: 'https://discord.gg/kbPnYJjvwZ', 32 | permanent: false, 33 | }, 34 | ]; 35 | }, 36 | }; 37 | 38 | const sentryWebpackPluginOptions = { silent: true }; 39 | 40 | module.exports = withSentryConfig(transpiled(nextConfig), sentryWebpackPluginOptions); 41 | -------------------------------------------------------------------------------- /pages/404.tsx: -------------------------------------------------------------------------------- 1 | import Error from 'next/error'; 2 | 3 | export default function NotFound() { 4 | // Opinionated: do not record an exception in Sentry for 404 5 | return ; 6 | } 7 | -------------------------------------------------------------------------------- /pages/api/revalidate.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from 'next'; 2 | 3 | export default async function handler(req: NextApiRequest, res: NextApiResponse){ 4 | // Check for secret to confirm this is a valid request 5 | if (req.query.secret !== process.env.REVALIDATION_SECRET) { 6 | return res.status(401).json({ message: 'Invalid token' }) 7 | } 8 | if(!(typeof req.query.path === 'string')){ 9 | return res.status(400).json({ message: `Invalid path argument: ${req.query.path}` }) 10 | } 11 | 12 | try { 13 | // this should be the actual path not a rewritten path 14 | // e.g. for "/blog/[slug]" this should be "/blog/post-1" 15 | await res.revalidate(req.query.path) 16 | return res.json({ revalidated: true }) 17 | } catch (err) { 18 | // If there was an error, Next.js will continue 19 | // to show the last successfully generated page 20 | return res.status(500).send('Error revalidating') 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | import { useRouter } from 'next/router'; 3 | 4 | function useV1Redirect() { 5 | const { push } = useRouter(); 6 | const redirectChecked = useRef(false); 7 | 8 | useEffect(() => { 9 | if (typeof window !== 'undefined' && window.location.hash && !redirectChecked.current) { 10 | const hash = window.location.hash; 11 | 12 | redirectChecked.current = true; 13 | 14 | if (hash.indexOf('#/pool/') === 0) { 15 | const poolId = hash.slice(7, 74); 16 | 17 | push(`/pool/${poolId}`); 18 | } else if (hash.indexOf('#/pools') === 0) { 19 | push('/pools'); 20 | } else if (hash.indexOf('#/trade') === 0) { 21 | push('/swap'); 22 | } 23 | } 24 | }); 25 | } 26 | 27 | function HomePage() { 28 | useV1Redirect(); 29 | 30 | return null; 31 | } 32 | 33 | export default HomePage; 34 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/favicon.ico -------------------------------------------------------------------------------- /public/fonts/gotham-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-bold-webfont.woff -------------------------------------------------------------------------------- /public/fonts/gotham-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-bold-webfont.woff2 -------------------------------------------------------------------------------- /public/fonts/gotham-book-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-book-webfont.woff -------------------------------------------------------------------------------- /public/fonts/gotham-book-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-book-webfont.woff2 -------------------------------------------------------------------------------- /public/fonts/gotham-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-light-webfont.woff -------------------------------------------------------------------------------- /public/fonts/gotham-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-light-webfont.woff2 -------------------------------------------------------------------------------- /public/fonts/gotham-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-medium-webfont.woff -------------------------------------------------------------------------------- /public/fonts/gotham-medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/fonts/gotham-medium-webfont.woff2 -------------------------------------------------------------------------------- /public/images/hero-image-fantom-mobile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/images/hero-image-fantom-mobile.jpg -------------------------------------------------------------------------------- /public/images/hero-image-fantom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/images/hero-image-fantom.jpg -------------------------------------------------------------------------------- /public/images/hero-image-optimism-mobile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/images/hero-image-optimism-mobile.jpg -------------------------------------------------------------------------------- /public/images/hero-image-optimism.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beethovenxfi/beets-frontend/0b53ad4a691de2965e7b52d8ffd66f22416fc2bc/public/images/hero-image-optimism.jpg -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /sentry.client.config.js: -------------------------------------------------------------------------------- 1 | // This file configures the initialization of Sentry on the browser. 2 | // The config you add here will be used whenever a page is visited. 3 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/ 4 | 5 | import * as Sentry from '@sentry/nextjs'; 6 | 7 | const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN; 8 | 9 | Sentry.init({ 10 | dsn: SENTRY_DSN, 11 | // Adjust this value in production, or use tracesSampler for greater control 12 | tracesSampleRate: 1.0, 13 | // ... 14 | // Note: if you want to override the automatic release value, do not set a 15 | // `release` value here - use the environment variable `SENTRY_RELEASE`, so 16 | // that it will also get attached to your source maps 17 | beforeSend(event, hint) { 18 | const error = hint.originalException; 19 | if ( 20 | error.name.toString().includes('TransactionError') && 21 | !error.message.toString().includes('User rejected request') 22 | ) { 23 | return event; 24 | } 25 | return null; 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /sentry.edge.config.js: -------------------------------------------------------------------------------- 1 | // This file configures the initialization of Sentry on the server. 2 | // The config you add here will be used whenever middleware or an Edge route handles a request. 3 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/ 4 | 5 | import * as Sentry from '@sentry/nextjs'; 6 | 7 | const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN; 8 | 9 | Sentry.init({ 10 | dsn: SENTRY_DSN, 11 | // Adjust this value in production, or use tracesSampler for greater control 12 | tracesSampleRate: 1.0, 13 | // ... 14 | // Note: if you want to override the automatic release value, do not set a 15 | // `release` value here - use the environment variable `SENTRY_RELEASE`, so 16 | // that it will also get attached to your source maps 17 | beforeSend(event, hint) { 18 | const error = hint.originalException; 19 | if ( 20 | error.name.toString().includes('TransactionError') && 21 | !error.message.toString().includes('User rejected request') 22 | ) { 23 | return event; 24 | } 25 | return null; 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /sentry.properties: -------------------------------------------------------------------------------- 1 | defaults.url=https://sentry.io/ 2 | defaults.org=skloon 3 | defaults.project=frontend 4 | cli.executable=node_modules\\@sentry\\cli\\bin\\sentry-cli 5 | -------------------------------------------------------------------------------- /sentry.server.config.js: -------------------------------------------------------------------------------- 1 | // This file configures the initialization of Sentry on the server. 2 | // The config you add here will be used whenever the server handles a request. 3 | // https://docs.sentry.io/platforms/javascript/guides/nextjs/ 4 | 5 | import * as Sentry from '@sentry/nextjs'; 6 | 7 | const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN; 8 | 9 | Sentry.init({ 10 | dsn: SENTRY_DSN, 11 | // Adjust this value in production, or use tracesSampler for greater control 12 | tracesSampleRate: 1.0, 13 | // ... 14 | // Note: if you want to override the automatic release value, do not set a 15 | // `release` value here - use the environment variable `SENTRY_RELEASE`, so 16 | // that it will also get attached to your source maps 17 | beforeSend(event, hint) { 18 | const error = hint.originalException; 19 | if ( 20 | error.name.toString().includes('TransactionError') && 21 | !error.message.toString().includes('User rejected request') 22 | ) { 23 | return event; 24 | } 25 | return null; 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /styles/Reliquary.module.css: -------------------------------------------------------------------------------- 1 | .overlapGrid { 2 | display: grid; 3 | height: 200px; 4 | width: 400px; 5 | grid-template-areas: 'overlay'; 6 | } 7 | 8 | .overlapGrid > div > div:nth-child(1), 9 | .overlapGrid > div > span:nth-child(1) { 10 | height: 200px !important; 11 | width: 200px !important; 12 | left: 100px; 13 | } 14 | 15 | .overlapGrid > div:nth-child(1), 16 | .overlapGrid > span:nth-child(1) { 17 | height: 200px !important; 18 | width: 450px !important; 19 | left: -25px; 20 | } 21 | 22 | @media only screen and (max-width: 400px) { 23 | .overlapGrid > div:nth-child(1), 24 | .overlapGrid > span:nth-child(1) { 25 | width: 90% !important; 26 | left: 15px; 27 | } 28 | } 29 | 30 | .overlapGrid > span, 31 | .overlapGrid > div { 32 | grid-area: overlay; 33 | } 34 | -------------------------------------------------------------------------------- /styles/chakraTheme.ts: -------------------------------------------------------------------------------- 1 | // chakraTheme.ts 2 | 3 | // 1. import `extendTheme` function 4 | import { ComponentStyleConfig, extendTheme, ThemeConfig } from '@chakra-ui/react'; 5 | import { fantomTheme } from '~/styles/themes/fantomTheme'; 6 | import { optimismTheme } from '~/styles/themes/optimismTheme'; 7 | 8 | // 2. Add your color mode config 9 | const config: ThemeConfig = { 10 | initialColorMode: 'dark', 11 | useSystemColorMode: false, 12 | }; 13 | 14 | const siteTheme = process.env.NEXT_PUBLIC_CHAIN_ID === '10' ? optimismTheme : fantomTheme; 15 | 16 | // 3. extend the chakraTheme 17 | export const chakraTheme = extendTheme({ 18 | ...siteTheme, 19 | config, 20 | components: { 21 | ...siteTheme.components, 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": "./", 18 | "paths": { 19 | "~/*": ["./*"] 20 | }, 21 | "downlevelIteration": true 22 | }, 23 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 24 | "exclude": ["node_modules"] 25 | } 26 | -------------------------------------------------------------------------------- /types/react-table-config.d.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-table 2 | import { 3 | UseExpandedHooks, 4 | UseExpandedInstanceProps, 5 | UseExpandedOptions, 6 | UseExpandedRowProps, 7 | UseExpandedState, 8 | } from 'react-table'; 9 | 10 | declare module 'react-table' { 11 | export interface TableOptions> extends UseExpandedOptions {} 12 | 13 | export interface Hooks = Record> extends UseExpandedHooks {} 14 | 15 | export interface TableInstance = Record> 16 | extends UseExpandedInstanceProps {} 17 | 18 | export interface TableState = Record> 19 | extends UseExpandedState {} 20 | 21 | export interface Row = Record> extends UseExpandedRowProps {} 22 | } 23 | --------------------------------------------------------------------------------