Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo } from "react"
import { useAccount } from "wagmi"
import { useStakingAssetTokenDetails } from "@/hooks/stakingRegistry"
import { useFeeAssetTokenDetails } from "@/hooks/rollup"
import { useIsRewardsClaimable } from "@/hooks/rollup/useIsRewardsClaimable"
import { useSplitsWarehouse } from "@/hooks/splits/useSplitsWarehouse"
import { useTransactionCart } from "@/contexts/TransactionCartContext"
Expand Down Expand Up @@ -59,7 +59,7 @@ export const ClaimAllDelegationRewardsButton = ({
onSuccess,
}: ClaimAllDelegationRewardsButtonProps) => {
const { address: beneficiary } = useAccount()
const { stakingAssetAddress: tokenAddress, decimals, symbol } = useStakingAssetTokenDetails()
const { feeAssetAddress: tokenAddress, decimals, symbol } = useFeeAssetTokenDetails()
const { isRewardsClaimable } = useIsRewardsClaimable()
const { addTransaction, checkTransactionInQueue, openCart, replaceTransactionByTx } = useTransactionCart()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createPortal } from "react-dom"
import { useAccount } from "wagmi"
import { Icon } from "@/components/Icon"
import { useStakingAssetTokenDetails } from "@/hooks/stakingRegistry"
import { useFeeAssetTokenDetails } from "@/hooks/rollup"
import { useIsRewardsClaimable } from "@/hooks/rollup/useIsRewardsClaimable"
import { useSplitsWarehouse } from "@/hooks/splits/useSplitsWarehouse"
import { ClaimAllRewardsSummary } from "./ClaimAllRewardsSummary"
Expand Down Expand Up @@ -41,7 +41,7 @@ export const ClaimAllRewardsModal = ({
onSuccess,
}: ClaimAllRewardsModalProps) => {
const { address: beneficiary } = useAccount()
const { symbol, decimals, stakingAssetAddress: tokenAddress } = useStakingAssetTokenDetails()
const { symbol, decimals, feeAssetAddress: tokenAddress } = useFeeAssetTokenDetails()
const { isRewardsClaimable } = useIsRewardsClaimable()
const { addTransaction, openCart, replaceTransactionByTx } = useTransactionCart()
const { showAlert } = useAlert()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useAccount } from "wagmi"
import { useStakingAssetTokenDetails } from "@/hooks/stakingRegistry"
import { useFeeAssetTokenDetails } from "@/hooks/rollup"
import { useERC20Balance } from "@/hooks/erc20/useERC20Balance"
import { useWarehouseBalance } from "@/hooks/splits/useWarehouseBalance"
import { useSplitsWarehouse } from "@/hooks/splits/useSplitsWarehouse"
Expand Down Expand Up @@ -50,7 +50,7 @@ export const ClaimDelegationRewardsButton = ({
variant = 'default'
}: ClaimDelegationRewardsButtonProps) => {
const { address: beneficiary } = useAccount()
const { stakingAssetAddress: tokenAddress, decimals, symbol } = useStakingAssetTokenDetails()
const { feeAssetAddress: tokenAddress, decimals, symbol } = useFeeAssetTokenDetails()

const { warehouseAddress } = useSplitsWarehouse(splitContract)
const { balance: splitContractBalance } = useERC20Balance(tokenAddress!, splitContract)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Icon } from "@/components/Icon"
import { CopyButton } from "@/components/CopyButton"
import { Tooltip } from "@/components/Tooltip"
import { formatTokenAmount } from "@/utils/atpFormatters"
import { useStakingAssetTokenDetails } from "@/hooks/stakingRegistry"
import { useFeeAssetTokenDetails } from "@/hooks/rollup"
import { ClaimDelegationRewardsButton } from "@/components/ClaimDelegationRewardsButton"
import { useWarehouseBalance } from "@/hooks/splits/useWarehouseBalance"
import { useCoinbaseRewardsAcrossRollups } from "@/hooks/rewards/useCoinbaseRewardsAcrossRollups"
Expand Down Expand Up @@ -46,7 +46,7 @@ export const ClaimDelegationRewardsModal = ({
onSuccess
}: ClaimDelegationRewardsModalProps) => {
const { address: beneficiary } = useAccount()
const { symbol, decimals, stakingAssetAddress: tokenAddress } = useStakingAssetTokenDetails()
const { symbol, decimals, feeAssetAddress: tokenAddress } = useFeeAssetTokenDetails()

// Get warehouse address from split contract
const { warehouseAddress } = useSplitsWarehouse(delegation.splitContract)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { formatTokenAmount, formatTokenAmountFull } from "@/utils/atpFormatters"
import { validateAddress } from "@/utils/validateAddress"
import { RollupRewardRow } from "./RollupRewardRow"
import { debounce } from "@/utils/debounce"
import { useStakingAssetTokenDetails } from "@/hooks/stakingRegistry"
import { useFeeAssetTokenDetails } from "@/hooks/rollup"
import { buildClaimSequencerRewardsTx } from "@/utils/claimCart"
import { useIsRewardsClaimableAcrossRollups } from "@/hooks/rollup/useIsRewardsClaimableAcrossRollups"
import { useCoinbaseRewardsAcrossRollups } from "@/hooks/rewards/useCoinbaseRewardsAcrossRollups"
Expand Down Expand Up @@ -42,7 +42,7 @@ export const ClaimSelfStakeRewardsModal = ({
atp,
onSuccess,
}: ClaimSelfStakeRewardsModalProps) => {
const { symbol, decimals } = useStakingAssetTokenDetails()
const { symbol, decimals } = useFeeAssetTokenDetails()
const [coinbaseAddress, setCoinbaseAddress] = useState("")
const [hasCheckedRewards, setHasCheckedRewards] = useState(false)
const [isDebouncing, setIsDebouncing] = useState(false)
Expand Down
13 changes: 13 additions & 0 deletions staking-dashboard/src/contracts/abis/Rollup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
export const RollupAbi = [
{
"type": "function",
"name": "getFeeAsset",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract IERC20"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "getExitDelay",
Expand Down
4 changes: 2 additions & 2 deletions staking-dashboard/src/hooks/atp/useAggregatedStakingData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ERC20Abi } from '@/contracts/abis/ERC20'
import { SplitAbi } from '@/contracts/abis/Split'
import { SplitWarehouseAbi } from '@/contracts/abis/SplitWarehouse'
import { calculateTotalUserShareFromSplitRewards } from '@/utils/rewardCalculations'
import { useStakingAssetTokenDetails } from '@/hooks/stakingRegistry'
import { useFeeAssetTokenDetails } from '@/hooks/rollup'
import { contracts, getRollupVersions, type RollupVersion } from '@/contracts'
import type { Address } from 'viem'
import { stringToBigInt } from '@/utils/atpFormatters'
Expand Down Expand Up @@ -478,7 +478,7 @@ function parseErc20DirectStake(stake: ApiErc20DirectStake): Erc20DirectStakeBrea
*/
export const useAggregatedStakingData = (): AggregatedStakingData => {
const { address } = useAccount()
const { stakingAssetAddress: tokenAddress } = useStakingAssetTokenDetails()
const { feeAssetAddress: tokenAddress } = useFeeAssetTokenDetails()

// Fetch staking data from API
const {
Expand Down
1 change: 1 addition & 0 deletions staking-dashboard/src/hooks/rollup/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { useRollupData } from "./useRollupData";
export { useActivationThresholdFormatted } from "./useActivationThresholdFormatted";
export { useSequencerRewards } from "./useSequencerRewards";
export { useFeeAssetTokenDetails } from "./useFeeAssetTokenDetails";
export { useIsRewardsClaimable } from "./useIsRewardsClaimable";
export { useIsRewardsClaimableAcrossRollups } from "./useIsRewardsClaimableAcrossRollups";
export { useEjectionThreshold } from "./useEjectionThreshold";
Expand Down
56 changes: 56 additions & 0 deletions staking-dashboard/src/hooks/rollup/useFeeAssetTokenDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useReadContract } from "wagmi"
import { useERC20TokenDetails } from "../erc20/useERC20TokenDetails"
import { contracts } from "../../contracts"
import type { Address } from "viem"

/**
* Hook to get the fee asset token details from the canonical rollup.
*
* Sequencer rewards are denominated in the rollup's FEE asset
* (`Rollup.getFeeAsset()`), NOT the staking asset. On mainnet the two are the
* same token, but on testnet they differ — using the staking asset in the
* claim pipeline made `Split.distribute()` distribute a zero balance while
* the actual fee-asset rewards sat stranded on the split contract. Any code
* that reads, distributes, or withdraws sequencer rewards must use this hook
* rather than `useStakingAssetTokenDetails`.
*/
export function useFeeAssetTokenDetails() {
const { data: feeAssetAddress, isLoading: isLoadingAddress, error: addressError } = useReadContract({
abi: contracts.rollup.abi,
address: contracts.rollup.address,
functionName: "getFeeAsset",
query: {
staleTime: Infinity,
gcTime: Infinity,
},
})

const {
tokenDetails,
isLoading: isLoadingTokenDetails,
name,
symbol,
decimals,
totalSupply
} = useERC20TokenDetails(feeAssetAddress as Address)

return {
// Fee asset address (reward token)
feeAssetAddress: feeAssetAddress as Address | undefined,

// Token details
tokenDetails,
name,
symbol,
decimals,
totalSupply,

// Loading states
isLoading: isLoadingAddress || isLoadingTokenDetails,
isLoadingAddress,
isLoadingTokenDetails,

// Error handling
error: addressError,
}
}
4 changes: 2 additions & 2 deletions staking-dashboard/src/hooks/splits/useTotalSplitRewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useSequencerRewards } from "@/hooks/rollup/useSequencerRewards"
import { useERC20Balance } from "@/hooks/erc20/useERC20Balance"
import { useWarehouseBalance } from "./useWarehouseBalance"
import { useSplitsWarehouse } from "./useSplitsWarehouse"
import { useStakingAssetTokenDetails } from "@/hooks/stakingRegistry"
import { useFeeAssetTokenDetails } from "@/hooks/rollup"
import { calculateTotalUserShareFromSplitRewards, calculateUserShareFromTakeRate } from "@/utils/rewardCalculations"
import type { Address } from "viem"

Expand All @@ -16,7 +16,7 @@ export const useTotalSplitRewards = (
beneficiary: Address | undefined,
providerTakeRate: number
) => {
const { stakingAssetAddress: tokenAddress } = useStakingAssetTokenDetails()
const { feeAssetAddress: tokenAddress } = useFeeAssetTokenDetails()

// Get warehouse address from split contract
const { warehouseAddress } = useSplitsWarehouse(splitContractAddress)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useReadContracts } from 'wagmi'
import type { Address } from 'viem'
import { ERC20Abi } from '@/contracts/abis/ERC20'
import { calculateTotalUserShareFromSplitRewards } from '@/utils/rewardCalculations'
import { useStakingAssetTokenDetails } from '@/hooks/stakingRegistry'
import { useFeeAssetTokenDetails } from '@/hooks/rollup'
import { contracts, getRollupVersions, type RollupVersion } from '@/contracts'
import type { Delegation } from '@/hooks/atp'
import type { StakeWithProviderReward } from './types'
Expand All @@ -28,7 +28,7 @@ export const useMultipleStakeWithProviderRewards = ({
delegations,
enabled = true
}: MultipleStakeWithProviderRewardsParams) => {
const { stakingAssetAddress: tokenAddress } = useStakingAssetTokenDetails()
const { feeAssetAddress: tokenAddress } = useFeeAssetTokenDetails()

// Rollups enumerated oldest first. Raw version ids are uint256s; we replace
// them with 1-based ordinals ("v1", "v2", …) for display.
Expand Down
4 changes: 2 additions & 2 deletions staking-dashboard/src/pages/Operator/OperatorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PageHeader } from "@/components/PageHeader"
import { Icon } from "@/components/Icon"
import { CopyButton } from "@/components/CopyButton"
import { TooltipIcon } from "@/components/Tooltip"
import { useStakingAssetTokenDetails } from "@/hooks/stakingRegistry"
import { useFeeAssetTokenDetails } from "@/hooks/rollup"
import { useIsRewardsClaimable } from "@/hooks/rollup/useIsRewardsClaimable"
import {
useConnectedOperatorIdentities,
Expand Down Expand Up @@ -56,7 +56,7 @@ export default function OperatorPage() {
hasError: identitiesError,
refetch: refetchIdentities,
} = useConnectedOperatorIdentities()
const { symbol, decimals, stakingAssetAddress: tokenAddress } = useStakingAssetTokenDetails()
const { symbol, decimals, feeAssetAddress: tokenAddress } = useFeeAssetTokenDetails()
const { isRewardsClaimable } = useIsRewardsClaimable()
// Cosmetic filter — historical delegations are kept in the underlying data
// (a now-exited delegator might still have unclaimed rollup rewards on the
Expand Down
Loading