Skip to content
This repository has been archived by the owner on Jun 16, 2022. It is now read-only.

Commit

Permalink
LIVE-1751 Solana staking (#4884)
Browse files Browse the repository at this point in the history
* add solana memo field

* add allow not created recipient checkbox

* tweak allow not created recipient checkbox

* update yarn.lock

* remove local specifics

* restore yarn.lock

* solana: add backbone for opt in flow

* solana improve opt in flow

* solana adapt reworked tx model

* solana add en translations for errors

* solana add info link to send flow

* solana switch to common info

* solana remove redundant error

* solana improve send memo

* solana remove token related code

* solana initial staking

* solana improve staking

* solana improve staking

* solana improve staking

* solana use stakes with meta

* solana add meta to validators

* solana make validators searchable

* solana improve staking

* solana fix delegation amount

* solana add stake reward

* solana add unstake flow modal

* solana show correct delegation dialogs

* solana add delegation modals

* solana build undelegate flow modal

* solana build delegation reactivate flow modal

* solana build delegation withdraw modal flow

* solana build delegation modal flow

* solana improve delegation ux

* solana improve delegation ux

* solana improve staking ux

* solana address mandatory autodelegate on staking

* solana add delegation activate flow

* solana rename error prop

* solana switch to validators app validators

* solana refactor delegation validators

* solana fallback to explorer if no validator url

* solana show correct stakes meta info

* solana add fee error to stake withdraw

* solana show fee error on stake withdraw & activate

* solana add validator step to stake deactivate

* solana add validator step to reactivate stake

* solana update delegated amount of a stake

* solana use shuffled staking validators

* solana refine validators search

* solana clean delegations

* solana organize imports

* solana update tracking info

* solana add delegation translations

* solana set live-common dep

* solana add loading icon to stake in transition

* solana fix stake tooltip color

* solana add account balance summary footer

* solana add staking info modal

* solana refactor staking validators field

* solana move validator row to a shared cmp

* solana update stake validator row

* solana add border around validators field

* solana switch to ledger by figment TC footer for staking flow

* solana fix stake reactivate error i18n

* solana fix wrong package url

* solana update yarn lock

* Target LLC branch family/solana

* Update Help Center staking Solana URL (#4885)

* solana refactor stake active percent calc

* solana show percent as fixed number

* Update targeted LLC commit

* Fix the link for LedgerByFigment's T&C

* Be more resilient before 1st sync with staking data

Co-authored-by: konoart <[email protected]>
Co-authored-by: FabriceDautriat <[email protected]>
Co-authored-by: Kévin Lambert <[email protected]>
  • Loading branch information
4 people committed Apr 7, 2022
1 parent cc2fb7a commit 1e730c2
Show file tree
Hide file tree
Showing 43 changed files with 3,713 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/config/urls.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ export const urls = {
website: "https://elrond.com",
},
solana: {
staking: "https://support.ledger.com/hc/en-us/articles/4731749170461?docs=true",
recipient_info: "https://support.ledger.com",
ledgerByFigmentTC: "https://drive.google.com/file/d/1vlIh2gTwtbMon8_bzFQGjCLhTUqS5uQc",
},
};
12 changes: 10 additions & 2 deletions src/renderer/components/Delegation/ValidatorRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ const Row: ThemedComponent<{ active: boolean, disabled: boolean }> = styled(Box)
: ""}
`;

type ValidatorRowProps = {
export type ValidatorRowProps = {
validator: { address: string },
icon: React$Node,
title: React$Node,
Expand All @@ -188,6 +188,7 @@ type ValidatorRowProps = {
unit: Unit,
onMax?: () => void,
shouldRenderMax?: boolean,
className?: string,
};

const ValidatorRow = ({
Expand All @@ -207,6 +208,7 @@ const ValidatorRow = ({
unit,
onMax,
shouldRenderMax,
className,
}: ValidatorRowProps) => {
const inputRef = useRef();
const onTitleClick = useCallback(
Expand Down Expand Up @@ -269,7 +271,13 @@ const ValidatorRow = ({
);

return (
<Row style={style} disabled={!value && disabled} active={!!value} onClick={onRowClick}>
<Row
className={className}
style={style}
disabled={!value && disabled}
active={!!value}
onClick={onRowClick}
>
{icon}
<InfoContainer>
<Title onClick={onTitleClick}>
Expand Down
144 changes: 144 additions & 0 deletions src/renderer/families/solana/AccountBalanceSummaryFooter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// @flow

import { getAccountUnit } from "@ledgerhq/live-common/lib/account";
import { formatCurrencyUnit } from "@ledgerhq/live-common/lib/currencies";
import React from "react";
import { Trans } from "react-i18next";
import { useSelector } from "react-redux";
import styled from "styled-components";
import Box from "~/renderer/components/Box/Box";
import Discreet, { useDiscreetMode } from "~/renderer/components/Discreet";
import Text from "~/renderer/components/Text";
import ToolTip from "~/renderer/components/Tooltip";
import InfoCircle from "~/renderer/icons/InfoCircle";
import { localeSelector } from "~/renderer/reducers/settings";
import type { ThemedComponent } from "~/renderer/styles/StyleProvider";
import type { Account } from "@ledgerhq/live-common/lib/types";
import { BigNumber } from "bignumber.js";

const Wrapper: ThemedComponent<*> = styled(Box).attrs(() => ({
horizontal: true,
mt: 4,
p: 5,
pb: 0,
}))`
border-top: 1px solid ${p => p.theme.colors.palette.text.shade10};
`;

const BalanceDetail = styled(Box).attrs(() => ({
flex: "0.25 0 auto",
vertical: true,
alignItems: "start",
}))`
&:nth-child(n + 3) {
flex: 0.75;
}
`;

const TitleWrapper = styled(Box).attrs(() => ({ horizontal: true, alignItems: "center", mb: 1 }))``;

const Title = styled(Text).attrs(() => ({
fontSize: 4,
ff: "Inter|Medium",
color: "palette.text.shade60",
}))`
line-height: ${p => p.theme.space[4]}px;
margin-right: ${p => p.theme.space[1]}px;
`;

const AmountValue = styled(Text).attrs(() => ({
fontSize: 6,
ff: "Inter|SemiBold",
color: "palette.text.shade100",
}))``;

type Props = {
account: Account,
countervalue: any,
};

const AccountBalanceSummaryFooter = ({ account, countervalue }: Props) => {
const discreet = useDiscreetMode();
const locale = useSelector(localeSelector);
if (!account.solanaResources) return null;

const { spendableBalance: _spendableBalance, solanaResources } = account;

const { stakes } = solanaResources;

const _delegatedBalance = new BigNumber(
stakes.reduce((sum, s) => sum + (s.delegation?.stake ?? 0), 0),
);

const _delegatedWithdrawableBalance = new BigNumber(
stakes.reduce((sum, s) => sum + s.withdrawable, 0),
);

const unit = getAccountUnit(account);

const formatConfig = {
disableRounding: true,
alwaysShowSign: false,
showCode: true,
discreet,
locale,
};

const spendableBalance = formatCurrencyUnit(unit, _spendableBalance, formatConfig);

const delegatedBalance = formatCurrencyUnit(unit, _delegatedBalance, formatConfig);

const delegatedWithdrawableBalance = formatCurrencyUnit(
unit,
_delegatedWithdrawableBalance,
formatConfig,
);

return (
<Wrapper>
<BalanceDetail>
<ToolTip content={<Trans i18nKey="account.availableBalanceTooltip" />}>
<TitleWrapper>
<Title>
<Trans i18nKey="account.availableBalance" />
</Title>
<InfoCircle size={13} />
</TitleWrapper>
</ToolTip>
<AmountValue>
<Discreet>{spendableBalance}</Discreet>
</AmountValue>
</BalanceDetail>
<BalanceDetail>
<ToolTip content={<Trans i18nKey="solana.delegation.delegatedInfoTooltip" />}>
<TitleWrapper>
<Title>
<Trans i18nKey="account.delegatedAssets" />
</Title>
<InfoCircle size={13} />
</TitleWrapper>
</ToolTip>
<AmountValue>
<Discreet>{delegatedBalance}</Discreet>
</AmountValue>
</BalanceDetail>
{_delegatedWithdrawableBalance.gt(0) && (
<BalanceDetail>
<ToolTip content={<Trans i18nKey="solana.delegation.withdrawableInfoTooltip" />}>
<TitleWrapper>
<Title>
<Trans i18nKey="solana.delegation.withdrawableTitle" />
</Title>
<InfoCircle size={13} />
</TitleWrapper>
</ToolTip>
<AmountValue>
<Discreet>{delegatedWithdrawableBalance}</Discreet>
</AmountValue>
</BalanceDetail>
)}
</Wrapper>
);
};

export default AccountBalanceSummaryFooter;
5 changes: 5 additions & 0 deletions src/renderer/families/solana/AccountBodyHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// @flow

import Delegation from "./Delegation";

export default Delegation;
45 changes: 45 additions & 0 deletions src/renderer/families/solana/AccountHeaderManageActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// @flow
import { getMainAccount } from "@ledgerhq/live-common/lib/account";
import type { Account, AccountLike } from "@ledgerhq/live-common/lib/types";
import invariant from "invariant";
import { useCallback } from "react";
import { useTranslation } from "react-i18next";
import { useDispatch } from "react-redux";
import { openModal } from "~/renderer/actions/modals";
import IconChartLine from "~/renderer/icons/ChartLine";

type Props = {
account: AccountLike,
parentAccount: ?Account,
};

const AccountHeaderActions = ({ account, parentAccount }: Props) => {
const { t } = useTranslation();
const dispatch = useDispatch();

const onClick = useCallback(() => {
dispatch(
openModal("MODAL_SOLANA_REWARDS_INFO", {
account,
}),
);
}, [dispatch, account]);

const mainAccount = getMainAccount(account, parentAccount);
const { solanaResources } = mainAccount;

if (!solanaResources || solanaResources.stakes.length > 0) {
return null;
}

return [
{
key: "solana",
onClick: onClick,
icon: IconChartLine,
label: t("delegation.title"),
},
];
};

export default AccountHeaderActions;
65 changes: 65 additions & 0 deletions src/renderer/families/solana/Delegation/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// @flow

import React from "react";
import { Trans } from "react-i18next";
import styled from "styled-components";
import Box from "~/renderer/components/Box/Box";
import { HeaderWrapper } from "~/renderer/components/TableContainer";
import type { ThemedComponent } from "~/renderer/styles/StyleProvider";

export const TableLine: ThemedComponent<{}> = styled(Box).attrs(() => ({
ff: "Inter|SemiBold",
color: "palette.text.shade60",
horizontal: true,
alignItems: "center",
justifyContent: "flex-start",
fontSize: 3,
flex: 1.125,
pr: 2,
}))`
box-sizing: border-box;
&:last-child {
justify-content: flex-end;
flex: 0.5;
text-align: right;
white-space: nowrap;
}
`;

export const Header = () => (
<HeaderWrapper>
<TableLine>
<Trans i18nKey="delegation.validator" />
</TableLine>
<TableLine>
<Trans i18nKey="delegation.status" />
</TableLine>
<TableLine>
<Trans i18nKey="delegation.delegated" />
</TableLine>
<TableLine>
<Trans i18nKey="solana.delegation.active" />
</TableLine>
<TableLine>
<Trans i18nKey="solana.delegation.availableBalance" />
</TableLine>
<TableLine />
</HeaderWrapper>
);

export const UnbondingHeader = () => (
<HeaderWrapper>
<TableLine>
<Trans i18nKey="delegation.validator" />
</TableLine>
<TableLine>
<Trans i18nKey="delegation.status" />
</TableLine>
<TableLine>
<Trans i18nKey="delegation.delegated" />
</TableLine>
<TableLine>
<Trans i18nKey="delegation.completionDate" />
</TableLine>
</HeaderWrapper>
);
Loading

0 comments on commit 1e730c2

Please sign in to comment.