@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
116 lines (97 loc) • 3.72 kB
text/typescript
import { useEffect, useMemo, useState } from "react";
import { FIGMENT_SUI_VALIDATOR_ADDRESS } from "@ledgerhq/coin-sui/constants";
import { BigNumber } from "bignumber.js";
import { SuiAccount, SuiResources, SuiValidator, MappedStake } from "./types";
import { getAccountCurrency } from "../../account";
import { Unit } from "@ledgerhq/types-cryptoassets";
import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
import { getCurrentSuiPreloadData } from "@ledgerhq/coin-sui/preload";
import { getOperationExtra } from "@ledgerhq/coin-sui/getOperationExtra";
import { OperationType } from "@ledgerhq/types-live";
export function useSuiMappedStakingPositions(account: SuiAccount) {
const { validators } = getCurrentSuiPreloadData();
const stakingPositions = account.suiResources?.stakes;
const unit = getAccountCurrency(account).units[0];
return useMemo(
() => mapStakingPositions(stakingPositions ?? [], validators, unit),
[stakingPositions, validators, unit],
);
}
export function useGetExtraDetails(account: SuiAccount, type: OperationType, digest: string) {
if (!account.suiResources) {
account.suiResources = {};
}
if (!account.suiResources.cachedOps) {
account.suiResources.cachedOps = {};
}
const cache = account.suiResources.cachedOps;
const [data, setData] = useState(cache[digest]);
useEffect(() => {
if (type !== "DELEGATE" && type !== "UNDELEGATE") return;
if (data) return;
getOperationExtra(digest).then(result => {
setData(result);
cache[digest] = result;
});
}, [data, digest, cache, type]);
return data;
}
export function useLedgerFirstShuffledValidatorsSui(search: string) {
const { validators: unorderedValidators } = getCurrentSuiPreloadData();
const validators = reorderValidators(unorderedValidators);
return useMemo(() => {
if (validators.length === 0 || !search || search === "") {
return validators;
}
const lowercaseSearch = search.toLowerCase();
const filtered = validators.filter(
validator =>
validator.suiAddress?.toLowerCase().includes(lowercaseSearch) ||
validator.name.toLowerCase().includes(lowercaseSearch),
);
return filtered;
}, [validators, search]);
}
function reorderValidators(validators: SuiValidator[]): SuiValidator[] {
const sortedValidators = [...validators].sort((a, b) =>
new BigNumber(b.stakingPoolSuiBalance).minus(new BigNumber(a.stakingPoolSuiBalance)).toNumber(),
);
// move Ledger validator to the first position
const ledgerValidator = sortedValidators.find(
v => v.suiAddress === FIGMENT_SUI_VALIDATOR_ADDRESS,
);
if (ledgerValidator) {
const sortedValidatorsLedgerFirst = sortedValidators.filter(
v => v.suiAddress !== FIGMENT_SUI_VALIDATOR_ADDRESS,
);
sortedValidatorsLedgerFirst.unshift(ledgerValidator);
return sortedValidatorsLedgerFirst;
}
return sortedValidators;
}
type Stake = Required<SuiResources>["stakes"];
export const mapStakingPositions = (
stakingPositions: Stake,
validators: SuiValidator[],
unit: Unit,
): MappedStake[] => {
const data = stakingPositions.flatMap(sp =>
sp.stakes.map(s => ({ ...s, validatorAddress: sp.validatorAddress })),
);
return data.map<MappedStake>(sp => {
const rank = validators.findIndex(v => v.suiAddress === sp.validatorAddress);
const validator = validators[rank] ?? sp;
const formatConfig = {
disableRounding: false,
alwaysShowSign: false,
showCode: true,
};
return {
...sp,
rank,
validator,
stakedSuiId: sp.stakedSuiId,
formattedAmount: formatCurrencyUnit(unit, BigNumber(sp.principal), formatConfig),
};
});
};