@polkadot/types/interfaces#ActiveEraInfo TypeScript Examples

The following examples show how to use @polkadot/types/interfaces#ActiveEraInfo. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Guaranteeable.tsx    From crust-apps with Apache License 2.0 6 votes vote down vote up
function GuaranteeableDisplay ({ params }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();

  const { api } = useApi();
  const stakeLimit = useCall<Option<Balance>>(api.query.staking.stakeLimit, [params]);
  const activeEraInfo = useCall<ActiveEraInfo>(api.query.staking.activeEra);

  const activeEra = activeEraInfo && (JSON.parse(JSON.stringify(activeEraInfo)).index);

  const accountIdBonded = useCall<string | null>(api.query.staking.bonded, [params], transformBonded);
  const controllerActive = useCall<Balance | null>(api.query.staking.ledger, [accountIdBonded], transformLedger);
  const erasStakersStashExposure = useCall<Option<Exposure>>(api.query.staking.erasStakers, [activeEra, params]);
  const erasStakersStash = erasStakersStashExposure && (parseObj(erasStakersStashExposure).others.map((e: { who: any; }) => e.who));

  const stakersGuarantees = useCall<Guarantee[]>(api.query.staking.guarantors.multi, [erasStakersStash]);
  let totalStaked = new BN(Number(controllerActive).toString());

  if (stakersGuarantees) {
    for (const stakersGuarantee of stakersGuarantees) {
      if (parseObj(stakersGuarantee)) {
        for (const target of parseObj(stakersGuarantee)?.targets) {
          if (target.who.toString() == params?.toString()) {
            totalStaked = totalStaked?.add(new BN(Number(target.value).toString()));
          }
        }
      }
    }
  }

  return (
    <>
      <span className='highlight'>{t<string>('total stakes')} {formatBalance(totalStaked, { withUnit: true })} / {t<string>('stake limit')} { formatBalance(new BN(Number(stakeLimit).toString()))}</span>
    </>
  );
}
Example #2
Source File: index.tsx    From crust-apps with Apache License 2.0 6 votes vote down vote up
function useAddressCalls (api: ApiPromise, address: string, isMain?: boolean) {
  const params = useMemo(() => [address], [address]);
  const stakeLimit = useCall<BN>(api.query.staking.stakeLimit, params);
  const accountInfo = useCall<DeriveAccountInfo>(api.derive.accounts.info, params);
  const slashingSpans = useCall<SlashingSpans | null>(!isMain && api.query.staking.slashingSpans, params, transformSlashes);
  const activeEraInfo = useCall<ActiveEraInfo>(api.query.staking.activeEra);
  const activeEra = activeEraInfo && (JSON.parse(JSON.stringify(activeEraInfo)).index);
  const erasStakersStashExposure = useCall<Exposure>(api.query.staking.erasStakers, [activeEra, address]);
  const accountIdBonded = useCall<string | null>(api.query.staking.bonded, params, transformBonded);
  const controllerActive = useCall<Balance | null>(api.query.staking.ledger, [accountIdBonded], transformLedger);
  const erasStakersStash = erasStakersStashExposure && (parseObj(erasStakersStashExposure).others.map((e: { who: any; }) => e.who));

  const stakersGuarantees = useCall<Guarantee[]>(api.query.staking.guarantors.multi, [erasStakersStash]);
  let totalStaked = new BN(Number(controllerActive).toString());

  if (stakersGuarantees) {
    for (const stakersGuarantee of stakersGuarantees) {
      if (parseObj(stakersGuarantee)) {
        for (const target of parseObj(stakersGuarantee)?.targets) {
          if (target.who.toString() == address) {
            totalStaked = totalStaked?.add(new BN(Number(target.value).toString()));
          }
        }
      }
    }
  }

  return { accountInfo, slashingSpans, totalStaked, stakeLimit, activeEra };
}
Example #3
Source File: BoosterCountDown.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function BoosterCountDown({ }: Props): React.ReactElement<Props> {
    const { api } = useApi();
    const { t } = useTranslation();
    const endDate = Date.parse('2021-07-11 14:00');
    const activeEraInfo = useCall<ActiveEraInfo>(api.query.staking.activeEra);

    const activeEra = activeEraInfo && (JSON.parse(JSON.stringify(activeEraInfo)).index);

    const [{ day_ten, day_one,hour_ten, hour_one, minute_ten, minute_one, second_ten, second_one }, setCountdownInfo] = useState<CountDownType>({
        day_ten: 1,
        day_one: 0,
        hour_ten: 0,
        hour_one: 0,
        minute_ten: 0,
        minute_one: 0,
        second_ten: 0,
        second_one: 0
    });

    useEffect(() => {
        let now_time = new Date().getTime();
        var remaining = endDate - now_time;
        const timer = setInterval(() => {
            if (activeEra >= 756 && remaining > 1000) {
                remaining -= 1000;
                const day = Math.floor((remaining / 1000 / 3600) / 24)
                const hour = Math.floor((remaining / 1000 / 3600) % 24)
                const minute = Math.floor((remaining / 1000 / 60) % 60)
                const second = Math.floor(remaining / 1000 % 60)
                setCountdownInfo({
                    day_ten: Math.floor(day/10),
                    day_one: day % 10,
                    hour_ten: Math.floor(hour/10),
                    hour_one: hour %10,
                    minute_ten: Math.floor(minute / 10),
                    minute_one: minute % 10,
                    second_ten: Math.floor(second/10),
                    second_one: second % 10
                })
            } else {
                clearInterval(timer)
            }
        }, 1000)
    }, [activeEra]);

    return (
        <div style={{display: 'inline-block', 'fontWeight': 'bold', fontSize: '16px',  "wordWrap": "break-word", "wordBreak": "break-all"}}>
            {t<string>('Activities in progress,End time countdown')}
            &nbsp;{day_ten}&nbsp;{day_one}&nbsp;:&nbsp;{hour_ten}&nbsp;{hour_one}&nbsp;:&nbsp;{minute_ten}&nbsp;{minute_one}&nbsp;:&nbsp;{second_ten}&nbsp;{second_one}
        </div>
    );
}
Example #4
Source File: index.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function CsmStakingApp({ basePath, onStatusChange }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api, systemChain } = useApi();
  const activeEraInfo = useCall<ActiveEraInfo>(api.query.staking.activeEra);
  const activeEra = activeEraInfo && (JSON.parse(JSON.stringify(activeEraInfo)).index);
  const increasingFactor =  Math.pow(1.02, 80) * Math.pow(1.03, Math.min(activeEra-1224, 40));
  const overviewUrl = systemChain == 'Crust Maxwell' ? 'https://pd-api.crust.network/overview/' : 'http://crust-sg1.ownstack.cn:8866/overview/';
  const [providers, setProviders] = useState<DataProviderState[]>([]);
  const [summaryInfo, setSummaryInfo] = useState<SummaryInfo | null>();
  const [isLoading, setIsloading] = useState<boolean>(true);

  useEffect(() => {
    if (Number(increasingFactor)) {
      getOverviewInfo(overviewUrl, api, increasingFactor).then(res => {
        setProviders(res.providers)
        setSummaryInfo(res.summaryInfo)
        setIsloading(false);
      }).catch(() => setIsloading(true))
    }
  }, [api, httpGet, overviewUrl, increasingFactor]);

  const itemsRef = useRef([
    {
      isRoot: true,
      name: 'overview',
      text: t<string>('Overview')
    },
    {
      name: 'actions',
      text: t<string>('Account actions')
    },
    {
      name: 'easterEggsOrders',
      text: t<string>('Lucky Orders')
    }
  ]);

  return (
    <main className='accounts--App'>
      <header>
        <Tabs
          basePath={basePath}
          items={itemsRef.current}
        />
      </header>
      <Switch>
        <Route path={`${basePath}/actions`}>
          <Actions providers={providers?.map((e) => e.account)} />
        </Route>
        <Route path={`${basePath}/easterEggsOrders`}>
          <EasterEggsOrders />
        </Route>
        <Route basePath={basePath}
          onStatusChange={onStatusChange}>
          <Overview isLoading={isLoading}
            providers={providers}
            summaryInfo={summaryInfo} />
        </Route>

      </Switch>
    </main>
  );
}
Example #5
Source File: MainnetRewards.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function MainnetReward ({ children, className = '', label }: Props): React.ReactElement<Props> {
  const { api } = useApi();
  const { t } = useTranslation();
  const activeEraInfo = useCall<ActiveEraInfo>(api.query.staking.activeEra);

  const activeEra = activeEraInfo && (JSON.parse(JSON.stringify(activeEraInfo)).index);
  const marketPayout = useCall<any>(api.query.staking.erasMarketPayout, [activeEra]);
  const stakingRewards = new BN(3422.3134898087887).mul(UNIT)
  const total = marketPayout && stakingRewards.add(new BN(Number(marketPayout).toString()))

  return (
    <div className={className}>
      {label || ''}
      <FormatBalance
        value={total}
        withSi
        label={
          <Icon
            icon='info-circle'
            tooltip={`mainnet-reward-trigger`}
          />
        }
      >
        <Tooltip
          text={
            <>
              <div>
                <div className='faded'>{t('staking payout: {{stakingRewards}}', {
                  replace: {
                    stakingRewards: formatBalance(stakingRewards)
                  }
                })}</div>
                <div className='faded'>{t('market payout: {{marketPayout}}', {
                  replace: {
                    marketPayout: marketPayout && formatBalance(new BN(Number(marketPayout).toString()))
                  }
                })}</div>
              </div>
            </>
          }
          trigger={`mainnet-reward-trigger`}
        />
      </FormatBalance>
      {children}
    </div>
  );
}
Example #6
Source File: index.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Overview({ providers, isLoading, summaryInfo }: Props): React.ReactElement<Props> {
  const { t, i18n } = useTranslation();
  const { api } = useApi();
  // we have a very large list, so we use a loading delay
  // const [nameFilter, setNameFilter] = useState<string>('');
  const [, setProviders] = useState<DataProviderState[]>([]);
  const [toggles, setToggle] = useSavedFlags('csmStaking:overview', { withIdentity: false });
  const [favorites, toggleFavorite] = useFavorites(CSM_FAVS);
  const [{ sortBy, sortFromMax }, setSortBy] = useState<SortState>({ sortBy: 'storage', sortFromMax: false });
  const [sorted, setSorted] = useState<DataProviderState[] | undefined>();
  const [{ isQueryFiltered, nameFilter }, setNameFilter] = useState({ isQueryFiltered: false, nameFilter: '' });
  const endTime = Date.parse('2021-07-11 14:00');
  const [remaining, setRemaing] = useState<number>(endTime - new Date().getTime());
  const activeEraInfo = useCall<ActiveEraInfo>(api.query.staking.activeEra);

  const activeEra = activeEraInfo && (JSON.parse(JSON.stringify(activeEraInfo)).index);

  const labelsRef = useRef({
    storage: t<string>('data power'),
    csmLimit: t<string>('CSM stake limit'),
    effectiveCSM: t<string>('effective stakes'),
    stakedCSM: t<string>('total stakes'),
    guaranteeFee: t<string>('guarantee fee')
  });

  useEffect(() => {
    // let now_time = new Date().getTime();
    // var remaining = endTime - now_time;
    const timer = setInterval(() => {
        if (remaining > 1000) {
          setRemaing(remaining-1000)
        } else {
          clearInterval(timer)
        }
    }, 1000)
}, [activeEra]);

  const filtered = useMemo(
    () => providers && applyFilter(providers),
    [providers]
  );

  useEffect((): void => {
    const sortedProviders = sortProviders(providers, favorites);
    setProviders(sortedProviders)

  }, [providers, favorites]);

  const _sort = useCallback(
    (newSortBy: ProviderSortBy) => setSortBy(({ sortBy, sortFromMax }) => ({
      sortBy: newSortBy,
      sortFromMax: newSortBy === sortBy
        ? !sortFromMax
        : true
    })),
    []
  );

  useEffect((): void => {
    filtered && setSorted(
      sort(sortBy, sortFromMax, filtered)
    );
  }, [filtered, sortBy, sortFromMax]);

  const _renderRows = useCallback(
    (addresses?: DataProviderState[]): React.ReactNode[] =>
      (addresses || []).map((info): React.ReactNode => (
        <DataProvider
          key={info.account}
          info={info}
          filterName={nameFilter}
          withIdentity={toggles.withIdentity}
          toggleFavorite={toggleFavorite}
          isFavorite={info.isFavorite}
        />
      )),
    [nameFilter, setToggle, toggles, toggleFavorite]
  );

  const _setNameFilter = useCallback(
    (nameFilter: string, isQueryFiltered: boolean) => setNameFilter({ isQueryFiltered, nameFilter }),
    []
  );

  const header = useMemo(() => [
    [t('providers'), 'start', 2],
    ...(SORT_KEYS as (keyof typeof labelsRef.current)[]).map((header) => [
      <>{labelsRef.current[header]}<Icon icon={sortBy === header ? (sortFromMax ? 'chevron-down' : 'chevron-up') : 'minus'} /></>,
      `${sorted ? `isClickable ${sortBy === header ? 'highlight--border' : ''} number` : 'number'} ${CLASSES[header] || ''}`,
      1,
      () => _sort(header as 'storage')
    ]),

  ], [_sort, labelsRef, sortBy, sorted, sortFromMax, t])

  const filter = useMemo(() => (
    <Filtering
      nameFilter={nameFilter}
      setNameFilter={_setNameFilter}
      setWithIdentity={setToggle.withIdentity}
      withIdentity={toggles.withIdentity}
    >
    </Filtering>

  ), [nameFilter, _setNameFilter, setToggle, t, toggles]);

  const displayList = isQueryFiltered
    ? providers
    : sorted;

  return (<>
      <h3 style={{ "textAlign": 'center' }}>
        <span style={{ "wordWrap": "break-word", "wordBreak": "break-all", float: "left", 'display': 'inline-block' }}><span style={{ 'fontWeight': 'bold', fontSize: '16px' }}>
          <a href={i18n.language == 'zh' ? 'https://mp.weixin.qq.com/s/vLnuyU5gJCRcOSv_PrLAsw' : 'https://medium.com/crustnetwork/profit-data-activity-rules-3ef2c9b364c4'} target="_blank">
            {t<string>(`Learn more about "Profit Data" >>`)}</a>
        </span>
        </span>
        {remaining > 1000 ? (<section style={{'display': 'inline-block', "wordWrap": "break-word", "wordBreak": "break-all"}}>
          <span style={{"marginRight": "5px", 'fontWeight': 'bold', fontSize: '16px'}}><a href={i18n.language == 'zh' ? 'https://mp.weixin.qq.com/s/P3kCjhPNg9UUH8eLXpvvZg' : 'https://crustnetwork.medium.com/10x-for-10-days-data-power-boost-is-launched-fd6e05b44115'} target="_blank">{t<string>('Data Power Booster ? >>')}</a></span>
          <BoosterCountDown />
        </section>) : null}
        <span style={{ "wordWrap": "break-word", "wordBreak": "break-all", float: "right", 'display': 'inline-block' }}><span style={{ 'fontWeight': 'bold', fontSize: '16px' }}>
          <a href={i18n.language == 'zh' ? 'https://mp.weixin.qq.com/s/pp74MQMODwID_gkrbMdHug' : 'https://medium.com/crustnetwork/profit-data-data-power-rules-adjustments-and-upgrades-9fa406c6fc34'} target="_blank">
            {t<string>(`About "Data Power" >>`)}</a>
        </span>
        </span>
      </h3>
      {isLoading ? <Spinner noLabel /> : <Summary isLoading={isLoading} info={summaryInfo} />}
    <Table
      empty={!isLoading && t<string>('No funds staked yet. Bond funds to validate or nominate a validator')}
      header={header}
      filter={filter}
    >
      {isLoading ? undefined : _renderRows(displayList)}
    </Table>
  </>
  );
}
Example #7
Source File: index.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Account ({ allSlashes, className = '', info: { controllerId, destination, hexSessionIdNext, hexSessionIdQueue, isLoading, isOwnController, isOwnStash, isStashNominating, isStashValidating, nominating, sessionIds, stakingLedger, stashId }, isDisabled, targets }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api, systemChain } = useApi();
  const { queueExtrinsic } = useContext(StatusContext);
  const [isBondExtraOpen, toggleBondExtra] = useToggle();
  const [isInjectOpen, toggleInject] = useToggle();
  const [isKickOpen, toggleKick] = useToggle();
  const [isNominateOpen, toggleNominate] = useToggle();
  const [isCutGuaranteeOpen, toggleCutGuarantee] = useToggle();
  const [isRewardDestinationOpen, toggleRewardDestination] = useToggle();
  const [isSetControllerOpen, toggleSetController] = useToggle();
  const [isSetSessionOpen, toggleSetSession] = useToggle();
  const [isSettingsOpen, toggleSettings] = useToggle();
  const [isUnbondOpen, toggleUnbond] = useToggle();
  const [isRebondOpen, toggleRebond] = useToggle();
  const [isValidateOpen, toggleValidate] = useToggle();
  const { balancesAll, spanCount, stakingAccount } = useStashCalls(api, stashId);
  const activeEraInfo = useCall<ActiveEraInfo>(api.query.staking.activeEra);
  const activeEra = activeEraInfo && (JSON.parse(JSON.stringify(activeEraInfo)).index);
  const guarantors = useCall<Guarantee>(api.query.staking.guarantors, [stashId]);
  const [guaranteeTargets, setGuaranteeTargets] = useState<IndividualExposure[]>([]);
  const [stakeValue, setStakeValue] = useState<BN>(BN_ZERO);
  const guarantorInfo = guarantors && JSON.parse(JSON.stringify(guarantors));
  const validators = useCall<ValidatorId[]>(api.query.session.validators);
  const isMaxwell = systemChain === 'Crust Maxwell';

  const [role, setRole] = useState<string>('Bonded');

  useEffect(() => {
    const isGuarantor = guarantorInfo && guarantorInfo.targets.length != 0;
    const isValidator = validators && (validators.map(e => e.toString())?.indexOf(stashId) != -1);
    const isCandidate = targets && (targets.waitingIds?.indexOf(stashId) != -1);
    if (isGuarantor) {
      setRole('Guarantor');
    } else if (isCandidate) {
      setRole('Candidate');
    } else if (isValidator) {
      setRole('Validator');
    } else {
      setRole('Bonded');
    }
  }, [guarantorInfo, validators, activeEra, targets]);

  useEffect(() => {
    if (guarantorInfo != null) {
      setGuaranteeTargets(guarantorInfo.targets);
    }
  }, [guarantors, validators, activeEra]);

  useEffect(() => {
    setStakeValue(guaranteeTargets.reduce((total: BN, { value }) => { return total.add(new BN(Number(value).toString())); }, BN_ZERO));
  }, [guaranteeTargets, activeEra])

  const slashes = useMemo(
    () => extractSlashes(stashId, allSlashes),
    [allSlashes, stashId]
  );

  const withdrawFunds = useCallback(
    () => {
      queueExtrinsic({
        accountId: controllerId,
        extrinsic: api.tx.staking.withdrawUnbonded.meta.args.length === 1
          ? api.tx.staking.withdrawUnbonded(spanCount || 0)
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore (We are doing toHex here since we have a Vec<u8> input)
          : api.tx.staking.withdrawUnbonded()
      });
    },
    [api, controllerId, queueExtrinsic, spanCount]
  );

  const hasBonded = !!stakingAccount?.stakingLedger && !stakingAccount.stakingLedger.active.isEmpty;

  return (
    <tr className={className}>
      <td className='badge together'>
        {slashes.length !== 0 && (
          <Badge
            color='red'
            hover={t<string>('Slashed in era {{eras}}', {
              replace: {
                eras: slashes.map(({ era }) => formatNumber(era)).join(', ')
              }
            })}
            icon='skull-crossbones'
          />
        )}
      </td>
      <td className='address'>
        <AddressSmall value={stashId} />
        {isBondExtraOpen && (
          <BondExtra
            controllerId={controllerId}
            onClose={toggleBondExtra}
            stakingInfo={stakingAccount}
            stashId={stashId}
          />
        )}
        {isInjectOpen && (
          <InjectKeys onClose={toggleInject} />
        )}
        {isKickOpen && controllerId && (
          <KickNominees
            controllerId={controllerId}
            onClose={toggleKick}
            stashId={stashId}
          />
        )}
        {isNominateOpen && controllerId && (
          <Nominate
            controllerId={controllerId}
            nominating={nominating}
            onClose={toggleNominate}
            stashId={stashId}
            targets={targets}
          />
        )}
        {isCutGuaranteeOpen && controllerId && (
          <CutGuarantee
            controllerId={controllerId}
            nominating={nominating}
            onClose={toggleCutGuarantee}
            stashId={stashId}
            targets={targets}
          />
        )}
        {isSetControllerOpen && controllerId && (
          <SetControllerAccount
            defaultControllerId={controllerId}
            onClose={toggleSetController}
            stashId={stashId}
          />
        )}
        {isRewardDestinationOpen && controllerId && (
          <SetRewardDestination
            controllerId={controllerId}
            defaultDestination={destination}
            onClose={toggleRewardDestination}
            stashId={stashId}
          />
        )}
        {isSetSessionOpen && controllerId && (
          <SetSessionKey
            controllerId={controllerId}
            onClose={toggleSetSession}
            stashId={stashId}
          />
        )}
        {isUnbondOpen && (
          <Unbond
            controllerId={controllerId}
            onClose={toggleUnbond}
            stakingLedger={stakingLedger}
            stashId={stashId}
          />
        )}
        {isRebondOpen && (
          <Rebond
            controllerId={controllerId}
            onClose={toggleRebond}
            stakingLedger={stakingLedger}
            stashId={stashId}
          />
        )}
        {isValidateOpen && controllerId && (
          <Validate
            controllerId={controllerId}
            onClose={toggleValidate}
            stashId={stashId}
          />
        )}
      </td>
      <td className='address'>
        <AddressMini value={controllerId} />
      </td>
      <td className='start media--1200'>
        {destination?.isAccount
          ? <AddressMini value={destination.asAccount} />
          : destination?.toString()
        }
      </td>
      <td className='number'>
        <StakingBonded stakingInfo={stakingAccount} />
        <StakingUnbonding stakingInfo={stakingAccount} />
        <StakingRedeemable stakingInfo={stakingAccount} />
      </td>
      {activeEra && (role !== 'Validator' && role !== 'Candidate')
        ? <EffectiveGuaranteed
          activeEra = {activeEra}
          stakeValue = {stakeValue}
          stashId= {stashId}
          validators = {guaranteeTargets}
        />
        : activeEra && (
          <EffectiveStake 
            activeEra={activeEra}
            stashId={stashId}
          />
        )
      }
      <td className='number ui--media-1200'>{t<string>('{{role}}', { replace: { role: role } })}</td>

      {isStashValidating
        ? (
          <td className='all'>
            <AddressInfo
              address={stashId}
              withBalance={false}
              withHexSessionId={hexSessionIdNext !== '0x' && [hexSessionIdQueue, hexSessionIdNext]}
              withValidatorPrefs
            />
          </td>
        )
        : (
          <td className='all expand left'>
            {isStashNominating && (
              <ListNominees
                nominating={nominating}
                stashId={stashId}
              />
            )}
          </td>
        )
      }
      <td className='button'>
        {!isLoading && (
          <>
            {(isStashNominating || isStashValidating)
              ? (
                <TxButton
                  accountId={controllerId}
                  icon='stop'
                  isDisabled={!isOwnController || isDisabled}
                  key='stop'
                  label={t<string>('Stop')}
                  tx={api.tx.staking.chill}
                />
              )
              : (
                <Button.Group>
                  {(!sessionIds.length || hexSessionIdNext === '0x')
                    ? (
                      <Button
                        icon='sign-in-alt'
                        isDisabled={!isOwnController || isDisabled}
                        key='set'
                        label={t<string>('Session Key')}
                        onClick={toggleSetSession}
                      />
                    )
                    : (
                      <Button
                        icon='certificate'
                        isDisabled={!isOwnController || isDisabled || !hasBonded}
                        key='validate'
                        label={t<string>('Validate')}
                        onClick={toggleValidate}
                      />
                    )
                  }
                  <Button
                    icon='hand-paper'
                    isDisabled={!isOwnController || isDisabled || !hasBonded}
                    key='nominate'
                    label={t<string>('Guarantee')}
                    onClick={toggleNominate}
                  />
                </Button.Group>
              )
            }
            <Popup
              isOpen={isSettingsOpen}
              key='settings'
              onClose={toggleSettings}
              trigger={
                <Button
                  icon='ellipsis-v'
                  isDisabled={isDisabled}
                  onClick={toggleSettings}
                />
              }
            >
              <Menu
                onClick={toggleSettings}
                text
                vertical
              >
                Bond
                <Menu.Item
                  disabled={!isOwnStash || !balancesAll?.freeBalance.gtn(0)}
                  onClick={toggleBondExtra}
                >
                  {t<string>('Bond more funds')}
                </Menu.Item>
                <Menu.Item
                  disabled={!isOwnController || !stakingAccount || !stakingAccount.stakingLedger || stakingAccount.stakingLedger.active.isEmpty}
                  onClick={toggleUnbond}
                >
                  {t<string>('Unbond funds')}
                </Menu.Item>
                <Menu.Item
                  disabled={!isOwnController || !stakingAccount || !stakingAccount.stakingLedger }
                  onClick={toggleRebond}
                >
                  {t<string>('Rebond funds')}
                </Menu.Item>
                <Menu.Item
                  disabled={!isOwnController || !stakingAccount || !stakingAccount.redeemable || !stakingAccount.redeemable.gtn(0)}
                  onClick={withdrawFunds}
                >
                  {t<string>('Withdraw unbonded funds')}
                </Menu.Item>
                <Menu.Item
                  disabled={!isOwnStash}
                  onClick={toggleSetController}
                >
                  {t<string>('Change controller account')}
                </Menu.Item>
                {isMaxwell && (<Menu.Item
                  disabled={!isOwnController}
                  onClick={toggleRewardDestination}
                >
                  {t<string>('Change reward destination')}
                </Menu.Item>)}
                <Menu.Divider />
                {
                  (role !== 'Bonded' && role != 'Guarantor' ) ? <> 
                    { 'Validate' }
                  {isStashValidating && (
                    <>
                      <Menu.Item
                        disabled={!isOwnController}
                        onClick={toggleValidate}
                      >
                        {t<string>('Change validator preferences')}
                      </Menu.Item>
                      {isFunction(api.tx.staking.kick) && (
                        <Menu.Item
                          disabled={!isOwnController}
                          onClick={toggleKick}
                        >
                          {t<string>('Remove nominees')}
                        </Menu.Item>
                      )}
                    </>
                  )}
                    {
                      <Menu.Item
                        disabled={!isOwnController}
                        onClick={toggleSetSession}
                      >
                        {t<string>('Change session keys')}
                      </Menu.Item>
                    }

                    {
                      <Menu.Item onClick={toggleInject}>
                        {t<string>('Inject session keys (advanced)')}
                      </Menu.Item>
                    } 

                  </> : null
                }
                
                {(role !== 'Validator' && role != 'Candidate' ) ? <>
                  <Menu.Divider />
                  { 'Guarantee' }
                  {
                    <Menu.Item
                      disabled={!isOwnController || !targets.validators?.length}
                      onClick={toggleNominate}
                    >
                      {t<string>('Guarantee')}
                    </Menu.Item>
                  }
                  {
                    <Menu.Item
                      disabled={!isOwnController || !targets.validators?.length}
                      onClick={toggleCutGuarantee}
                    >
                      {t<string>('Cut guarantee')}
                    </Menu.Item>
                  }
                </> : null
                } 
              </Menu>
            </Popup>
          </>
        )}
      </td>
    </tr>
  );
}