Skip to content

Commit

Permalink
frontend: update 'My portfolio' with Lightning account
Browse files Browse the repository at this point in the history
This commit adds functionality to display Lightning account
in 'My portfolio' in cases where it is active but not associated
with a connected or remembered wallet, or when all mainnet
accounts in the connected wallet are disabled.

The total coins table is updated to include the Lightning account,
and the Lightning configuration now also contains the keystore
name.
  • Loading branch information
strmci committed Jun 24, 2024
1 parent 011c90c commit 547408d
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 6 deletions.
1 change: 1 addition & 0 deletions backend/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func TestSetLightningConfig(t *testing.T) {
Code: "v0-test-ln-0",
Number: 0,
RootFingerprint: []byte("fingerprint"),
KeyStoreName: "test",
})
require.NoError(t, cfg.SetLightningConfig(lightningCfg))

Expand Down
2 changes: 2 additions & 0 deletions backend/config/lightning.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ type LightningAccountConfig struct {
Mnemonic string `json:"mnemonic"`
// RootFingerprint is fingerprint of the keystore that generated the entropy.
RootFingerprint jsonp.HexBytes `json:"rootFingerprint"`
// KeyStoreName is name of the keystore.
KeyStoreName string `json:"keystoreName"`
// Code is the code of the lightning account.
Code types.Code `json:"code"`
// Number is the lightning account incremental number.
Expand Down
17 changes: 13 additions & 4 deletions backend/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -765,9 +765,9 @@ func (handlers *Handlers) getAccountsBalance(*http.Request) (interface{}, error)
}

type coinFormattedAmount struct {
CoinCode coin.Code `json:"coinCode"`
CoinName string `json:"coinName"`
FormattedAmount accountHandlers.FormattedAmount `json:"formattedAmount"`
CoinCode coin.Code `json:"coinCode"`
CoinName string `json:"coinName"`
FormattedAmount coin.FormattedAmount `json:"formattedAmount"`
}

// getCoinsTotalBalance returns the total balances grouped by coins.
Expand All @@ -776,6 +776,15 @@ func (handlers *Handlers) getCoinsTotalBalance(_ *http.Request) (interface{}, er
var sortedCoins []coin.Code
totalCoinsBalances := make(map[coin.Code]*big.Int)

if handlers.backend.Config().LightningConfig().LightningEnabled() {
lightningBalance, err := handlers.backend.Lightning().Balance()
if err != nil {
return nil, err
}
totalCoinsBalances[coin.CodeBTC] = lightningBalance.Available().BigInt()
sortedCoins = append(sortedCoins, coin.CodeBTC)
}

for _, account := range handlers.backend.Accounts() {
if account.Config().Config.Inactive || account.Config().Config.HiddenBecauseUnused {
continue
Expand Down Expand Up @@ -810,7 +819,7 @@ func (handlers *Handlers) getCoinsTotalBalance(_ *http.Request) (interface{}, er
coinFormattedAmounts = append(coinFormattedAmounts, coinFormattedAmount{
CoinCode: coinCode,
CoinName: currentCoin.Name(),
FormattedAmount: accountHandlers.FormattedAmount{
FormattedAmount: coin.FormattedAmount{
Amount: currentCoin.FormatAmount(coin.NewAmount(totalCoinsBalances[coinCode]), false),
Unit: currentCoin.GetFormatUnit(false),
Conversions: coin.Conversions(
Expand Down
6 changes: 6 additions & 0 deletions backend/lightning/lightning.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ func (lightning *Lightning) Activate() error {
return err
}

keystoreName, err := keystore.Name()
if err != nil {
return err
}

entropyMnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
lightning.log.WithError(err).Warn("Error generating mnemonic")
Expand All @@ -111,6 +116,7 @@ func (lightning *Lightning) Activate() error {
lightningAccount := config.LightningAccountConfig{
Mnemonic: entropyMnemonic,
RootFingerprint: fingerprint,
KeyStoreName: keystoreName,
Code: types.Code(strings.Join([]string{"v0-", hex.EncodeToString(fingerprint), "-ln-0"}, "")),
Number: 0,
}
Expand Down
1 change: 1 addition & 0 deletions frontends/web/src/api/lightning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface ILightningResponse<T> {
export type TLightningAccountConfig = {
mnemonic: string;
rootFingerprint: string;
keystoreName: string;
code: AccountCode;
num: number;
};
Expand Down
24 changes: 22 additions & 2 deletions frontends/web/src/routes/account/summary/accountssummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { Status } from '../../../components/status/status';
import { GuideWrapper, GuidedContent, Header, Main } from '../../../components/layout';
import { View } from '../../../components/view/view';
import { Chart } from './chart';
import { SummaryBalance } from './summarybalance';
import { LightningBalance, SummaryBalance } from './summarybalance';
import { CoinBalance } from './coinbalance';
import { AddBuyReceiveOnEmptyBalances } from '../info/buyReceiveCTA';
import { Entry } from '../../../components/guide/entry';
Expand All @@ -36,6 +36,7 @@ import { HideAmountsButton } from '../../../components/hideamountsbutton/hideamo
import { AppContext } from '../../../contexts/AppContext';
import { getAccountsByKeystore, isAmbiguiousName } from '../utils';
import { RatesContext } from '../../../contexts/RatesContext';
import { useLightning } from '../../../hooks/lightning';

type TProps = {
accounts: accountApi.IAccount[];
Expand All @@ -60,9 +61,25 @@ export function AccountsSummary({ accounts, devices }: TProps) {
const [accountsTotalBalance, setAccountsTotalBalance] = useState<accountApi.TAccountsTotalBalance>();
const [coinsTotalBalance, setCoinsTotalBalance] = useState<accountApi.TCoinsTotalBalance>();
const [balances, setBalances] = useState<Balances>();
const { lightningConfig } = useLightning();

const hasCard = useSDCard(devices);

// lightning account exists but is not from any connected or remembered keystores
const hasLightningFromOtherKeystore = (
lightningConfig.accounts.length !== 0
&& (
accountsByKeystore.length === 0
|| !accountsByKeystore.some(({ keystore }) => {
return keystore.rootFingerprint === lightningConfig.accounts[0].rootFingerprint;
})
)
);
let keystores = accountsByKeystore.length;
if (hasLightningFromOtherKeystore) {
keystores += 1;
}

const getAccountSummary = useCallback(async () => {
// replace previous timer if present
if (summaryReqTimerID.current) {
Expand Down Expand Up @@ -213,12 +230,15 @@ export function AccountsSummary({ accounts, devices }: TProps) {
<AddBuyReceiveOnEmptyBalances accounts={accounts} balances={balances} />
) : undefined
} />
{accountsByKeystore.length > 1 && (
{keystores > 1 && (
<CoinBalance
summaryData={summaryData}
coinsBalances={coinsTotalBalance}
/>
)}
{hasLightningFromOtherKeystore && (
<LightningBalance/>
)}
{accountsByKeystore &&
(accountsByKeystore.map(({ keystore, accounts }) =>
<SummaryBalance
Expand Down
48 changes: 48 additions & 0 deletions frontends/web/src/routes/account/summary/summarybalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,51 @@ export function SummaryBalance({
</div>
);
}


export function LightningBalance() {
const { t } = useTranslation();
const { lightningConfig } = useLightning();
const [lightningBalance, setLightningBalance] = useState<accountApi.IBalance>();

const fetchLightningBalance = useCallback(async () => {
setLightningBalance(await getLightningBalance());
}, []);

useEffect(() => {
fetchLightningBalance();
const subscriptions = [subscribeNodeState(fetchLightningBalance)];
return () => unsubscribe(subscriptions);
}, [fetchLightningBalance, lightningConfig]);

return (
<div>
<div className={style.accountName}>
<p>
{lightningConfig.accounts[0].keystoreName} ({lightningConfig.accounts[0].rootFingerprint})
</p>
</div>
<div className={style.balanceTable}>
<table className={style.table}>
<colgroup>
<col width="33%" />
<col width="33%" />
<col width="*" />
</colgroup>
<thead>
<tr>
<th>{t('accountSummary.name')}</th>
<th>{t('accountSummary.balance')}</th>
<th>{t('accountSummary.fiatBalance')}</th>
</tr>
</thead>
<tbody>
{lightningBalance && (
<BalanceRow key="lightning" code="lightning" name="Lightning" coinCode="lightning" balance={lightningBalance} />
)}
</tbody>
</table>
</div>
</div>
);
}

0 comments on commit 547408d

Please sign in to comment.