Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release / 5.3.100 #3613

Merged
merged 9 commits into from
Sep 2, 2024
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,42 +1,35 @@
import Button from '@mui/material/Button';
import { LoadingButton } from '@mui/lab';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { parseDrepId } from '@yoroi/staking';
import * as React from 'react';
import { RustModule } from '../../../../api/ada/lib/cardanoCrypto/rustLoader';
import { dRepToMaybeCredentialHex } from '../../../../api/ada/lib/cardanoCrypto/utils';
import { TextInput } from '../../../components/Input/TextInput';
import { useModal } from '../../../components/modals/ModalContext';
import { useGovernance } from '../module/GovernanceContextProvider';
import { useStrings } from './useStrings';

type ChooseDRepModallProps = {
onSubmit?: (drepId: string) => void;
onSubmit?: (drepId: string, drepCredential: string) => void;
};

export const ChooseDRepModal = ({ onSubmit }: ChooseDRepModallProps) => {
const [drepId, setDrepId] = React.useState('');
const [error, setError] = React.useState(false);

const { dRepIdChanged, governanceVoteChanged } = useGovernance();
const { isLoading } = useModal();
const strings = useStrings();

// TODO hook endpoint not working well
// const { error, isFetched, isFetching } = useIsValidDRepID(drepId, {
// retry: false,
// enabled: drepId.length > 0,
// });

React.useEffect(() => {
setError(false);
}, [drepId]);

const confirmDRep = () => {
parseDrepId(drepId, RustModule.CrossCsl.init('any'))
.then(_ => {
onSubmit?.(drepId);
})
.catch(_ => {
setError(true);
});
const dRepCredentialHex: string | null = dRepToMaybeCredentialHex(drepId);
if (dRepCredentialHex == null) {
setError(true);
} else {
onSubmit?.(drepId, dRepCredentialHex);
}
};

return (
Expand All @@ -57,13 +50,18 @@ export const ChooseDRepModal = ({ onSubmit }: ChooseDRepModallProps) => {
value={drepId}
error={error}
helperText={error ? strings.incorectFormat : ' '}
// defaultValue="drep1wn0dklu87w8d9pkuyr7jalulgvl9w2he0hn0fne9k5a6y4d55mt"
/>
</Stack>
{/* @ts-ignore */}
<Button onClick={confirmDRep} fullWidth variant="primary" disabled={error || drepId.length === 0}>
<LoadingButton
loading={isLoading}
onClick={confirmDRep}
fullWidth
// @ts-ignore
variant="primary"
disabled={error || drepId.length === 0}
>
{strings.confirm}
</Button>
</LoadingButton>
</Stack>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';
import { styled } from '@mui/material/styles';
import * as React from 'react';
import LoadingSpinner from '../../../../components/widgets/LoadingSpinner';
import { useGovernance } from '../module/GovernanceContextProvider';

type Props = {
title: string;
Expand All @@ -14,9 +16,10 @@ type Props = {
selected: boolean;
onClick: () => void;
pending: boolean;
loading: boolean;
};

const StyledCard: any = styled(Stack)(({ theme, selected, pending }: any) => ({
const StyledCard: any = styled(Stack)(({ theme, selected, pending, isDrepSelected }: any) => ({
position: 'relative',
display: 'flex',
flexDirection: 'column',
Expand All @@ -33,6 +36,7 @@ const StyledCard: any = styled(Stack)(({ theme, selected, pending }: any) => ({
...(selected && {
background: !pending && theme.palette.ds.bg_gradient_2,
border: 'none',
pointerEvents: !isDrepSelected && 'none',
}),
cursor: 'pointer',
...(pending && {
Expand All @@ -56,11 +60,11 @@ const Description = styled(Typography)(({ theme }) => ({
marginTop: theme.spacing(1),
}));

// const SpinnerBox = styled(Box)(() => ({
// position: 'absolute',
// right: 15,
// top: 15,
// }));
const SpinnerBox = styled(Box)(() => ({
position: 'absolute',
right: 15,
top: 15,
}));

export const GovernanceVoteingCard = ({
title,
Expand All @@ -71,17 +75,23 @@ export const GovernanceVoteingCard = ({
selected,
onClick,
pending = false,
loading = false,
}: Props) => {
const [hover, onHover] = React.useState(false);

const { governanceStatus } = useGovernance();
return (
<div onMouseOver={() => onHover(true)} onMouseLeave={() => onHover(false)}>
<StyledCard onClick={pending ? undefined : onClick} pending={pending === true ? 'true' : undefined} selected={selected}>
{/* {pending && selected && (
<StyledCard
onClick={pending ? undefined : onClick}
pending={pending === true ? 'true' : undefined}
selected={selected}
isDrepSelected={governanceStatus.status === 'delegate'}
>
{loading && (
<SpinnerBox>
<LoadingSpinner />
</SpinnerBox>
)} */}
)}
<CardContent>
<IconContainer>{icon}</IconContainer>
<Typography variant="h3" fontWeight="500" mt="16px">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import BigNumber from 'bignumber.js';
import moment from 'moment';
import { WalletTypeOption } from '../../../../api/ada/lib/storage/models/ConceptualWallet/interfaces';
import { maybe } from '../../../../coreUtils';
import { genLookupOrFail } from '../../../../stores/stateless/tokenHelpers';
import { calculateAndFormatValue } from '../../../../utils/unit-of-account';

Expand Down Expand Up @@ -89,14 +88,17 @@ export const getFormattedPairingValue = (getCurrentPrice, defaultTokenInfo, unit
};

const getTotalAmount = (walletAmount, rewards) => {
return maybe(walletAmount, w => rewards.joinAddCopy(w));
return walletAmount && rewards
? walletAmount.joinAddCopy(rewards)
: (walletAmount ?? rewards);
};

const getWalletTotalAdaBalance = (stores, selectedWallet) => {
const totalAmount = stores.transactions.getBalance(selectedWallet);
const rewards = stores.delegation.getRewardBalanceOrZero(selectedWallet);
const amount = getTotalAmount(totalAmount, rewards);
const defaultEntry = amount?.getDefaultEntry();
if (defaultEntry == null) return new BigNumber(0);
const getTokenInfo = genLookupOrFail(stores.tokenInfoStore.tokenInfo);
const tokenInfo = getTokenInfo(defaultEntry);
return defaultEntry.amount.shiftedBy(-tokenInfo.Metadata.numberOfDecimals);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const messages = Object.freeze(
},
drepId: {
id: 'governance.drepId',
defaultMessage: '!!!Drep ID:',
defaultMessage: '!!!Drep ID (Fingerprint):',
},
delegateToDRep: {
id: 'governance.delegateToDRep',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GovernanceApi } from '@emurgo/yoroi-lib/dist/governance/emurgo-api';
import { bech32 } from 'bech32';
import * as React from 'react';

import { RustModule } from '../../../../api/ada/lib/cardanoCrypto/rustLoader';
Expand Down Expand Up @@ -141,7 +142,9 @@ export const GovernanceContextProvider = ({
} else if (governanceStatusState && governanceStatusState.drepDelegation?.drep === 'no_confidence') {
setGovernanceStatus({ status: DREP_ALWAYS_NO_CONFIDENCE, drep: null });
} else if (governanceStatusState !== null && governanceStatusState.drepDelegation?.drep.length > 0) {
setGovernanceStatus({ status: 'delegate', drep: governanceStatusState.drepDelegation?.drep || null });
const words = bech32.toWords(Buffer.from(governanceStatusState.drepDelegation?.drep, 'hex'));
const encoded = bech32.encode('drep', words, 64);
setGovernanceStatus({ status: 'delegate', drep: encoded || null });
} else {
setGovernanceStatus({ status: 'none', drep: null });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,19 @@ export const GovernanceStatusSelection = () => {
walletAdaBalance,
triggerBuySellAdaDialog,
submitedTransactions,
governanceVote,
} = useGovernance();
const [error, setError] = React.useState<string | null>(null);
const [loadingUnsignTx, setLoadingUnsignTx] = React.useState<boolean>(false);
const navigateTo = useNavigateTo();
const strings = useStrings();
const { openModal, closeModal } = useModal();
const { openModal, closeModal, startLoading } = useModal();
const pageTitle = governanceStatus.status !== 'none' ? strings.governanceStatus : strings.registerGovernance;
const statusRawText = mapStatus[governanceStatus.status || ''];
const pageSubtitle = governanceStatus.status === 'none' ? strings.reviewSelection : strings.statusSelected(statusRawText);
const isPendindDrepDelegationTx = submitedTransactions.length > 0 && submitedTransactions[0]?.isDrepDelegation === true;

const openDRepIdModal = (onSubmit: (drepID: string) => void) => {
const openDRepIdModal = (onSubmit: (drepID: string, drepCredential: string) => void) => {
if (!governanceManager) {
return;
}
Expand All @@ -65,40 +67,46 @@ export const GovernanceStatusSelection = () => {
),
width: '648px',
height: '336px',
isLoading: loadingUnsignTx,
});
};

const handleDelegate = async () => {
openDRepIdModal(drepID => {
openDRepIdModal((drepID, drepCredential) => {
const vote: Vote = { kind: 'delegate', drepID };
createUnsignTx(drepID);
governanceVoteChanged(vote);
createUnsignTx(drepCredential);
});
};

const handleAbstain = async () => {
await createUnsignTx(DREP_ALWAYS_ABSTAIN);
const vote: Vote = { kind: DREP_ALWAYS_ABSTAIN };
governanceVoteChanged(vote);
await createUnsignTx(DREP_ALWAYS_ABSTAIN);
};

const handleNoConfidence = async () => {
await createUnsignTx(DREP_ALWAYS_NO_CONFIDENCE);
const vote: Vote = { kind: DREP_ALWAYS_NO_CONFIDENCE };
governanceVoteChanged(vote);
await createUnsignTx(DREP_ALWAYS_NO_CONFIDENCE);
};

const createUnsignTx = async kind => {
try {
await createDrepDelegationTransaction(kind);
setError(null);
navigateTo.delegationForm();
setLoadingUnsignTx(true);
startLoading();
setTimeout(async () => {
await createDrepDelegationTransaction(kind);
navigateTo.delegationForm();
setLoadingUnsignTx(false);
setError(null);
}, 200);
} catch (e) {
setError('Error trying to Vote. Please try again later');
closeModal();
setLoadingUnsignTx(false);
}
};

const optionsList = [
{
title: governanceStatus.status === 'delegate' ? strings.delegatingToDRep : strings.delegateToDRep,
Expand All @@ -111,23 +119,26 @@ export const GovernanceStatusSelection = () => {
icon: <DRepIlustration />,
selected: governanceStatus.status === 'delegate' ? true : false,
onClick: handleDelegate,
pending: isPendindDrepDelegationTx,
pending: isPendindDrepDelegationTx || loadingUnsignTx,
loading: loadingUnsignTx && governanceVote.kind === 'delegate',
},
{
title: strings.abstain,
description: strings.abstainInfo,
icon: <Abstein />,
selected: governanceStatus.status === DREP_ALWAYS_ABSTAIN ? true : false,
onClick: handleAbstain,
pending: isPendindDrepDelegationTx,
pending: isPendindDrepDelegationTx || loadingUnsignTx,
loading: loadingUnsignTx && governanceVote.kind === DREP_ALWAYS_ABSTAIN,
},
{
title: strings.noConfidence,
description: strings.noConfidenceInfo,
icon: <NoConfidance />,
selected: governanceStatus.status === DREP_ALWAYS_NO_CONFIDENCE ? true : false,
onClick: handleNoConfidence,
pending: isPendindDrepDelegationTx,
pending: isPendindDrepDelegationTx || loadingUnsignTx,
loading: loadingUnsignTx && governanceVote.kind === DREP_ALWAYS_NO_CONFIDENCE,
},
];

Expand Down Expand Up @@ -170,6 +181,7 @@ export const GovernanceStatusSelection = () => {
selected={option.selected}
onClick={option.onClick}
pending={option.pending}
loading={option.loading}
/>
);
})
Expand Down
16 changes: 16 additions & 0 deletions packages/yoroi-extension/app/api/ada/lib/cardanoCrypto/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ export function transactionHexReplaceWitnessSet(txHex: string, witnessSetHex: st
});
}

export function dRepToMaybeCredentialHex(s: string): ?string {
return RustModule.WasmScope(Module => {
try {
if (s.startsWith('drep1')) {
return Module.WalletV4.Credential
.from_keyhash(Module.WalletV4.Ed25519KeyHash.from_bech32(s)).to_hex();
}
if (s.startsWith('drep_script1')) {
return Module.WalletV4.Credential
.from_scripthash(Module.WalletV4.ScriptHash.from_bech32(s)).to_hex();
}
} catch {} // eslint-disable-line no-empty
return null;
})
}

export function pubKeyHashToRewardAddress(hex: string, network: number): string {
return RustModule.WasmScope(Module =>
Module.WalletV4.RewardAddress.new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { normalizeToAddress, unwrapStakingKey, } from './utils';
import type { IGetAllUtxosResponse, IGetStakingKey, } from '../models/PublicDeriver/interfaces';
import { MultiToken, } from '../../../../common/lib/MultiToken';
import { maybe, fail } from '../../../../../coreUtils';
import { isHex } from '@emurgo/yoroi-lib/dist/internals/utils/index';

export type GetDelegatedBalanceRequest = {|
publicDeriver: PublicDeriver<> & IGetStakingKey,
Expand Down Expand Up @@ -139,23 +138,20 @@ export async function getUtxoDelegatedBalance(
export const DREP_ALWAYS_ABSTAIN = 'ALWAYS_ABSTAIN';
export const DREP_ALWAYS_NO_CONFIDENCE = 'ALWAYS_NO_CONFIDENCE';

// <TODO:WASM_MONAD>
function parseKey(key: string): RustModule.WalletV4.Ed25519KeyHash {
return isHex(key)
? RustModule.WalletV4.Ed25519KeyHash.from_hex(key)
: RustModule.WalletV4.Ed25519KeyHash.from_bech32(key);
}

// <TODO:WASM_MONAD>
function parseDrep(drepCredential: string): RustModule.WalletV4.DRep {
const DRep = RustModule.WalletV4.DRep;
if (drepCredential === DREP_ALWAYS_ABSTAIN) return DRep.new_always_abstain();
if (drepCredential === DREP_ALWAYS_NO_CONFIDENCE) return DRep.new_always_no_confidence();
// <TODO:FIX> to handle script hashes
const credential = RustModule.WalletV4.Credential.from_keyhash(parseKey(drepCredential));
return maybe(credential.to_keyhash(), k => DRep.new_key_hash(k))
?? maybe(credential.to_scripthash(), s => DRep.new_script_hash(s))
?? fail('weird credential cannot be converted into a drep: ' + credential.to_hex())
try {
const DRep = RustModule.WalletV4.DRep;
if (drepCredential === DREP_ALWAYS_ABSTAIN) return DRep.new_always_abstain();
if (drepCredential === DREP_ALWAYS_NO_CONFIDENCE) return DRep.new_always_no_confidence();
const credential = RustModule.WalletV4.Credential.from_hex(drepCredential);
return maybe(credential.to_keyhash(), k => DRep.new_key_hash(k))
?? maybe(credential.to_scripthash(), s => DRep.new_script_hash(s))
?? fail('weird credential cannot be converted into a drep: ' + credential.to_hex())
} catch (e) {
console.log('Fail to parse a drep credential: ' + drepCredential, e);
throw e;
}
}

// <TODO:WASM_MONAD>
Expand Down
Loading
Loading