Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
7 changes: 7 additions & 0 deletions packages/yoroi-extension/app/UI/common/helpers/formatters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function truncateFormatter(addr: string, cutoff: number): string {
const shortener = '...';
if (addr.length - shortener.length <= cutoff) {
return addr;
}
return addr.substring(0, cutoff / 2) + shortener + addr.substring(addr.length - cutoff / 2, addr.length);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import React from 'react';

export const YoroiLogo = (props: React.SVGProps<SVGSVGElement>) => {
return (
<svg width="33" height="28" viewBox="0 0 33 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg
width={props.width || '33'}
height={props.height || '28'}
viewBox="0 0 33 28"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M18.035 6.29133C17.4616 6.6752 16.8881 7.05907 16.3147 7.45005C16.157 7.54957 16.0566 7.56379 15.8989 7.45005C14.494 6.48325 13.0747 5.51645 11.6554 4.54965C10.1788 3.51176 8.70212 2.47387 7.21115 1.4502L5.10372 0H0C0.147125 0.0998317 0.277521 0.191368 0.402482 0.279089C0.508873 0.353774 0.611331 0.425698 0.716814 0.497618C1.38345 0.952582 2.05009 1.4111 2.71673 1.86962C3.38331 2.3281 4.05006 2.7867 4.71664 3.24162L8.67345 5.97141C9.28938 6.39757 9.90889 6.82728 10.5284 7.25699L10.53 7.25811C11.15 7.68819 11.7701 8.11828 12.3865 8.5448C12.8397 8.85722 13.2951 9.16752 13.7509 9.47815C14.4772 9.97315 15.2054 10.4695 15.9276 10.976C16.0566 11.0613 16.1427 11.0613 16.2717 10.976C16.813 10.6019 17.359 10.237 17.907 9.87084C18.3169 9.59694 18.7279 9.32228 19.1389 9.04242C21.4901 7.43583 23.8412 5.82923 26.1924 4.23686C27.8984 3.07101 29.6188 1.90516 31.3248 0.753535C31.5534 0.599354 31.7762 0.445173 32.0043 0.287301C32.1336 0.197807 32.2652 0.106758 32.4 0.0142176H27.2819C25.9503 0.912269 24.6226 1.81833 23.2926 2.72603C22.1169 3.5284 20.9393 4.33205 19.7554 5.13257C19.182 5.52353 18.6084 5.90747 18.035 6.29133Z"
fill={props.fill || 'currentColor'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { dRepToMaybeCredentialHex } from '../../../../api/ada/lib/cardanoCrypto/
import { TextInput } from '../../../components/Input/TextInput';
import { useModal } from '../../../components/modals/ModalContext';
import { useGovernance } from '../module/GovernanceContextProvider';
import { useStrings } from './useStrings';
import { useStrings } from './hooks/useStrings';

type ChooseDRepModallProps = {
onSubmit?: (drepId: string, drepCredential: string) => void;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import * as React from 'react';
import { NotEnoughMoneyToSendError } from '../../../../../api/common/errors';
import { dRepToMaybeCredentialHex } from '../../../../../api/ada/lib/cardanoCrypto/utils';
import { TransactionResult } from '../../../transaction-review/common/types';
import { useGovernance } from '../../module/GovernanceContextProvider';
import { useTxReviewModal } from '../../../transaction-review/module/ReviewTxProvider';
import { useStrings } from './useStrings';
import { Vote } from '../../module/state';
import { DREP_ALWAYS_ABSTAIN, DREP_ALWAYS_NO_CONFIDENCE } from '../../common/constants';

type UseGovernanceDelegationResult = {
loadingUnsignTx: boolean;
error: string | null;
setError: (value: string | null) => void;

// 1) direct delegation to a specific DRep (Yoroi or any other)
delegateToDrep: (drepID: string) => Promise<void>;

// 2) open modal to choose DRep id & delegate
openDelegateModalForCustomDrep: () => void;

// 3) always abstain
delegateToAbstain: () => Promise<void>;

// 4) always no-confidence
delegateToNoConfidence: () => Promise<void>;
};

export const useGovernanceDelegationToYoroiDrep = (): UseGovernanceDelegationResult => {
const [error, setError] = React.useState<string | null>(null);
const [loadingUnsignTx, setLoadingUnsignTx] = React.useState<boolean>(false);

const strings = useStrings();

const { governanceVoteChanged, createDrepDelegationTransaction, signDelegationTransaction, selectedWallet, governanceManager } =
useGovernance();

const {
openTxReviewModal,
startLoadingTxReview,
stopLoadingTxReview,
changePasswordInputValue,
showTxResultModal,
setDrepId,
setUnsignedTx,
drepCredentialHex,
} = useTxReviewModal();

const signGovernanceTx = React.useCallback(
async (password: string) => {
try {
startLoadingTxReview();
await signDelegationTransaction({
password,
wallet: selectedWallet,
dialog: null,
});
stopLoadingTxReview();
changePasswordInputValue({ type: 'changeInputValue', passswordInput: '' });
showTxResultModal(TransactionResult.SUCCESS);
} catch (error) {
console.warn('[createDrepDelegationTransaction,signDelegationTransaction]', error);
stopLoadingTxReview();
showTxResultModal(TransactionResult.FAIL);
}
},
[
startLoadingTxReview,
stopLoadingTxReview,
signDelegationTransaction,
selectedWallet,
changePasswordInputValue,
showTxResultModal,
]
);

const createUnsignTx = React.useCallback(
async (dRepCredentialHex: string | null) => {
try {
setLoadingUnsignTx(true);
const txSignRequest: any = await createDrepDelegationTransaction(dRepCredentialHex || '');

openTxReviewModal({
modalView: 'transactionReview',
unsignedTx: txSignRequest.signTxRequest.unsignedTx,
submitTx: (password: string) => {
void signGovernanceTx(password);
},
operations: {
kind: 'delegate vote',
},
});

setError(null);
} catch (e) {
if (e instanceof NotEnoughMoneyToSendError) {
setError(strings.notEnoughMoneyToSendError);
} else {
setError('Error trying to Vote. Please try again later');
}
} finally {
setLoadingUnsignTx(false);
}
},
[createDrepDelegationTransaction, openTxReviewModal, signGovernanceTx, strings]
);

/** 1) Delegate to a specific DRep (Yoroi or any other) */
const delegateToDrep = React.useCallback(
async (drepID: string) => {
const vote: Vote = { kind: 'delegate', drepID };
const dRepCredentialHex: string | null = dRepToMaybeCredentialHex(drepID);

governanceVoteChanged(vote);
setDrepId({ drepID });
await createUnsignTx(dRepCredentialHex);
},
[governanceVoteChanged, setDrepId, createUnsignTx]
);

/** 2) Open modal to choose a custom DRep */
const openDelegateModalForCustomDrep = React.useCallback(() => {
if (!governanceManager) {
return;
}

const vote: Vote = { kind: 'delegate', drepID: drepCredentialHex ?? '' };
governanceVoteChanged(vote);

openTxReviewModal({
title: 'CHOOSE YOUR DREP',
modalView: 'chooseOtherDrepId',
createUnsignedTx: async (value: string) => {
try {
startLoadingTxReview();
const txSignRequest: any = await createDrepDelegationTransaction(value);
setUnsignedTx({
type: 'setUnsignedTx',
unsignedTx: txSignRequest.signTxRequest.unsignedTx,
});
} finally {
stopLoadingTxReview();
}
},
submitTx: (password: string) => {
void signGovernanceTx(password);
},
operations: {
kind: 'delegate vote',
},
});
}, [
governanceManager,
governanceVoteChanged,
drepCredentialHex,
openTxReviewModal,
startLoadingTxReview,
stopLoadingTxReview,
createDrepDelegationTransaction,
setUnsignedTx,
signGovernanceTx,
]);

/** 3) Always abstain */
const delegateToAbstain = React.useCallback(async () => {
const vote: Vote = { kind: DREP_ALWAYS_ABSTAIN };

governanceVoteChanged(vote);
// For abstain / no-confidence we usually just pass the constant to the tx creation
await createUnsignTx(DREP_ALWAYS_ABSTAIN);
}, [governanceVoteChanged, createUnsignTx]);

/** 4) Always no-confidence */
const delegateToNoConfidence = React.useCallback(async () => {
const vote: Vote = { kind: DREP_ALWAYS_NO_CONFIDENCE };

governanceVoteChanged(vote);
await createUnsignTx(DREP_ALWAYS_NO_CONFIDENCE);
}, [governanceVoteChanged, createUnsignTx]);

return {
loadingUnsignTx,
error,
setError,
delegateToDrep,
openDelegateModalForCustomDrep,
delegateToAbstain,
delegateToNoConfidence,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as React from 'react';
import { useGovernance } from '../../module/GovernanceContextProvider';
import { GOVERNANCE_STATUS, GovernanceStatusState } from '../../common/constants';

type UseGovernanceStatusStateResult = {
governanceStatusState: GovernanceStatusState;
governanceStatus: ReturnType<typeof useGovernance>['governanceStatus'];
isPendingDrepDelegationTx: boolean;
};

export const useGovernanceStatusState = (): UseGovernanceStatusStateResult => {
const { governanceStatus, submitedTransactions } = useGovernance();

const isPendingDrepDelegationTx = submitedTransactions.length > 0 && submitedTransactions[0]?.isDrepDelegation === true;

const governanceStatusState: GovernanceStatusState = React.useMemo(() => {
if (governanceStatus.status === 'none' && governanceStatus.drep === null) {
return GOVERNANCE_STATUS.IDLE;
}
if (governanceStatus.status === 'delegate' && governanceStatus.drep !== null) {
return GOVERNANCE_STATUS.DELEGATED;
}
if (isPendingDrepDelegationTx) {
return GOVERNANCE_STATUS.DISABLED;
}
return GOVERNANCE_STATUS.IDLE;
}, [governanceStatus.status, governanceStatus.drep, isPendingDrepDelegationTx]);

return {
governanceStatusState,
governanceStatus,
isPendingDrepDelegationTx,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { networks } from '../../../../../api/ada/lib/storage/database/prepackaged/networks';
import { useGovernance } from '../../module/GovernanceContextProvider';

export const useIsGovernanceAllowed = () => {
const { governanceStatus, walletAdaBalance, networkId } = useGovernance();

const isParticipating = governanceStatus.status != null && governanceStatus.status !== 'none';

const hasZeroAda = walletAdaBalance !== null && walletAdaBalance === 0;
const isTestnet = networkId !== networks.CardanoMainnet.NetworkId;

const isNotAllowed = !isParticipating && hasZeroAda;

return {
isNotAllowed,
isParticipating,
hasZeroAda,
isTestnet,
};
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { defineMessages } from 'react-intl';
import { useIntl } from 'react-intl';
import globalMessages from '../../../../i18n/global-messages';
import globalMessages from '../../../../../i18n/global-messages';

export const messages = Object.freeze(
defineMessages({
Expand Down Expand Up @@ -226,8 +226,8 @@ export const messages = Object.freeze(
'!!!You are designating someone else to cast your vote on your behalf for all proposals now and in the future.',
},
chooseAbstain: {
id: 'governance.chooseAbstain',
defaultMessage: '!!!Choose to abstain from voting while still participating in the governance process and earning rewards.',
id: 'governance.abstainInfo',
defaultMessage: '!!!You are choosing not to cast a vote on all proposals now and in the future.',
},
chooseNoConfidence: {
id: 'governance.chooseNoConfidence',
Expand All @@ -237,6 +237,23 @@ export const messages = Object.freeze(
id: 'governance.changeToDrep',
defaultMessage: '!!!Change to DRep',
},
delegateToOtherDrep: {
id: 'governance.delegateToOtherDrep',
defaultMessage: '!!!Delegate to other DRep',
},
delegatingLabel: {
id: 'governance.delegatingLabel',
defaultMessage: '!!!Delegateing',
},
delegationStatus: {
id: 'governance.delegationStatus',
defaultMessage: '!!!Delegation status',
},
votingPowerInfo: {
id: 'governance.votingPowerInfo',
defaultMessage:
'!!!Your voting power is currently delegated and contributing to Cardano’s decision-making. You remain free to adjust your delegation whenever you choose.',
},
})
);

Expand Down Expand Up @@ -302,5 +319,9 @@ export const useStrings = () => {
chooseAbstain: intl.formatMessage(messages.chooseAbstain),
chooseNoConfidence: intl.formatMessage(messages.chooseNoConfidence),
changeToDrep: intl.formatMessage(messages.changeToDrep),
delegateToOtherDrep: intl.formatMessage(messages.delegateToOtherDrep),
delegatingLabel: intl.formatMessage(messages.delegatingLabel),
delegationStatus: intl.formatMessage(messages.delegationStatus),
votingPowerInfo: intl.formatMessage(messages.votingPowerInfo),
}).current;
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { PasswordInput } from '../../../../components/Input/PasswordInput';
import { DREP_ALWAYS_ABSTAIN, DREP_ALWAYS_NO_CONFIDENCE } from '../../common/constants';
import { dRepNormalize, dRepToPreCip129 } from '../../../../../api/ada/lib/cardanoCrypto/utils';
import { useNavigateTo } from '../../common/useNavigateTo';
import { useStrings } from '../../common/useStrings';
import { useStrings } from '../../common/hooks/useStrings';
import { useGovernance } from '../../module/GovernanceContextProvider';
import { mapStatus } from '../SelectGovernanceStatus/GovernanceStatusSelection';
import { maybe } from '../../../../../coreUtils';
Expand Down
Loading
Loading