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

Trezor wallet governance actions support #3732

Merged
merged 6 commits into from
Nov 15, 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
Expand Up @@ -4,17 +4,22 @@ import { FormattedMessage } from 'react-intl';
import globalMessages from '../../../i18n/global-messages';
import { useNavigateTo } from '../../features/governace/common/useNavigateTo';
import { FailedIlustration } from './FailedIlustration';
import LocalizableError from '../../../i18n/LocalizableError';

export const TransactionFailed = () => {
export const TransactionFailed = (props: { error: Error | null }) => {
const navigate = useNavigateTo();
const { error } = props;

return (
<Stack alignItems="center" mt="110px">
<FailedIlustration />
<Typography variant="h5" fontWeight="500" mt={4} mb={1}>
<FormattedMessage {...globalMessages.transactionFailed} />
</Typography>
<Typography variant="body1" mb={2} color="ds.text_gray_low">
<FormattedMessage {...globalMessages.transactionFailedInfo} />
<FormattedMessage {...(
error instanceof LocalizableError ? error : globalMessages.transactionFailedInfo
)}/>
</Typography>
{/* @ts-ignore */}
<Button variant="primary" onClick={() => navigate.selectStatus()}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Props = {
const GovernanceTransactionFailedPage = (props: Props): any => {
return (
<GovernanceLayout {...props}>
<TransactionFailed />
<TransactionFailed error={props.stores.substores.ada.delegationTransaction.error} />
</GovernanceLayout>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ import {
CardanoTxOutputSerializationFormat,
CardanoTxSigningMode,
CardanoTxWitnessType,
CardanoDRepType,
} from 'trezor-connect-flow';
import type { Address, Addressing, Value, } from '../../lib/storage/models/PublicDeriver/interfaces';
import { HaskellShelleyTxSignRequest } from './HaskellShelleyTxSignRequest';
import { Bip44DerivationLevels, } from '../../lib/storage/database/walletTypes/bip44/api/utils';
import { ChainDerivations, } from '../../../../config/numbersConfig';

import { RustModule } from '../../lib/cardanoCrypto/rustLoader';
import { range } from 'lodash';
import { toHexOrBase58 } from '../../lib/storage/bridge/utils';
import blake2b from 'blake2b';
import { derivePublicByAddressing } from '../../lib/cardanoCrypto/deriveByAddressing';
import { bytesToHex, iterateLenGet, iterateLenGetMap, maybe } from '../../../../coreUtils';
import { bytesToHex, iterateLenGet, iterateLenGetMap, maybe, forceNonNull } from '../../../../coreUtils';
import { mergeWitnessSets } from '../utils';

// ==================== TREZOR ==================== //
Expand Down Expand Up @@ -104,7 +104,7 @@ export function createTrezorSignTxPayload(
...request,
certificates: formatTrezorCertificates(
certificates,
range(0, certificates.len()).map(_i => stakingKeyPath),
(_) => stakingKeyPath,
)
};

Expand Down Expand Up @@ -161,35 +161,76 @@ function formatTrezorWithdrawals(
}))
.toArray();
}

function formatTrezorCertificates(
certificates: RustModule.WalletV4.Certificates,
paths: Array<Array<number>>,
getPath: (stakeCredential: RustModule.WalletV4.Credential) => Array<number>,
): Array<CardanoCertificate> {
const result = [];
for (const [cert, path] of iterateLenGet(certificates).zip(paths)) {
if (cert.as_stake_registration() != null) {
for (const cert of iterateLenGet(certificates)) {
const registrationCert = cert.as_stake_registration();
if (registrationCert != null) {
result.push({
type: CardanoCertificateType.STAKE_REGISTRATION,
path,
path: getPath(registrationCert.stake_credential()),
});
continue;
}
if (cert.as_stake_deregistration() != null) {
const deregistrationCert = cert.as_stake_deregistration();
if (deregistrationCert != null) {
result.push({
type: CardanoCertificateType.STAKE_DEREGISTRATION,
path,
path: getPath(deregistrationCert.stake_credential()),
});
continue;
}
const delegationCert = cert.as_stake_delegation();
if (delegationCert != null) {
result.push({
type: CardanoCertificateType.STAKE_DELEGATION,
path: getPath(delegationCert.stake_credential()),
pool: delegationCert.pool_keyhash().to_hex(),
path,
});
continue;
}
const voteDelegation = cert.as_vote_delegation();
if (voteDelegation != null) {
const wasmDrep = voteDelegation.drep();
let dRep;
switch (wasmDrep.kind()) {
case RustModule.WalletV4.DRepKind.KeyHash:
dRep = {
type: CardanoDRepType.KEY_HASH,
keyHash: forceNonNull(voteDelegation.drep().to_key_hash()).to_hex(),
};
break;
case RustModule.WalletV4.DRepKind.ScriptHash:
dRep = {
type: CardanoDRepType.KEY_HASH,
scriptHash: forceNonNull(voteDelegation.drep().to_script_hash()).to_hex(),
};
break;
case RustModule.WalletV4.DRepKind.AlwaysAbstain:
dRep = {
type: CardanoDRepType.ABSTAIN,
};
break;
case RustModule.WalletV4.DRepKind.AlwaysNoConfidence:
dRep = {
type: CardanoDRepType.NO_CONFIDENCE,
};
break;
default:
throw new Error('Trezor: Unsupported dRep kind: ' + wasmDrep.kind());
}
result.push({
type: CardanoCertificateType.VOTE_DELEGATION,
dRep,
path: getPath(voteDelegation.stake_credential()),
});
continue;
}
// TODO: @trezor/connect-web 9.4.2 hasn't supported dRep (de)registration and update
throw new Error(`${nameof(formatTrezorCertificates)} Trezor doesn't support this certificate type`);
}
return result;
Expand Down Expand Up @@ -708,37 +749,7 @@ export function toTrezorSignRequest(
}
return addressing;
};

const result = [];
for (const cert of iterateLenGet(certificates)) {
const registrationCert = cert.as_stake_registration();
if (registrationCert != null) {
result.push({
type: CardanoCertificateType.STAKE_REGISTRATION,
path: getPath(registrationCert.stake_credential()),
});
continue;
}
const deregistrationCert = cert.as_stake_deregistration();
if (deregistrationCert != null) {
result.push({
type: CardanoCertificateType.STAKE_DEREGISTRATION,
path: getPath(deregistrationCert.stake_credential()),
});
continue;
}
const delegationCert = cert.as_stake_delegation();
if (delegationCert != null) {
result.push({
type: CardanoCertificateType.STAKE_DELEGATION,
path: getPath(delegationCert.stake_credential()),
pool: delegationCert.pool_keyhash().to_hex(),
});
continue;
}
throw new Error(`unsupported certificate type`);
}
formattedCertificates = result;
formattedCertificates = formatTrezorCertificates(certificates, getPath);
}

let formattedWithdrawals = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import type { LayoutComponentMap } from '../../../styles/context/layout';
import type { StoresAndActionsProps } from '../../../types/injectedProps.types';
import type { $npm$ReactIntl$IntlFormat } from 'react-intl';
import { MultiToken } from '../../../api/common/lib/MultiToken';
import type { WalletType } from '../../../../chrome/extension/background/types';

// populated by ConfigWebpackPlugin
declare var CONFIG: ConfigType;
Expand Down Expand Up @@ -212,9 +211,7 @@ class StakingPageContent extends Component<AllProps> {
const delegatedUtxo = stores.delegation.getDelegatedUtxoBalance(publicDeriver.publicDeriverId);
const delegatedRewards = stores.delegation.getRewardBalanceOrZero(publicDeriver);

// <TODO:PENDING_REMOVAL> remove special check after governance for trezor is added
const isTrezor = (publicDeriver.type: WalletType) === 'trezor';
const isParticipatingToGovernance = stores.delegation.governanceStatus?.drepDelegation != null || isTrezor;
const isParticipatingToGovernance = stores.delegation.governanceStatus?.drepDelegation != null;

return (
<Box>
Expand Down
6 changes: 6 additions & 0 deletions packages/yoroi-extension/app/domain/TrezorLocalizedError.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const messages = defineMessages({
defaultMessage:
'!!!Could not sign the transaction. Please ensure the passphrase you entered is the passhprase used to create this wallet.',
},
conwayNotSupportedByFirmwareError: {
id: 'wallet.send.trezor.error.conway.firmware',
defaultMessage: '!!!Conway features not supported by your Trezor firmware version. Please upgrade to 2.8.1 or above.',
},
});

/** Converts error(from API or Trezor API) to LocalizableError */
Expand All @@ -35,6 +39,8 @@ export function convertToLocalizableError(error: Error): LocalizableError {
localizableError = new LocalizableError(messages.noWitnessError);
} else if (/Cancelled/.test(error.message)) {
localizableError = new LocalizableError(messages.signTxError101);
} else if (/Feature Conway not supported by device firmware/.test(error.message)) {
localizableError = new LocalizableError(messages.conwayNotSupportedByFirmwareError);
} else {
// Trezor device related error happend, convert then to LocalizableError
switch (error.message) {
Expand Down
1 change: 1 addition & 0 deletions packages/yoroi-extension/app/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,7 @@
"wallet.send.trezor.confirmationDialog.info.line.2": "A new tab will appear. Please follow the instructions in the new tab.",
"wallet.send.trezor.confirmationDialog.submit": "Send using Trezor",
"wallet.send.trezor.error.101": "Signing cancelled on Trezor device. Please retry",
"wallet.send.trezor.error.conway.firmware": "Conway features not supported by your Trezor firmware version. Please upgrade to 2.8.1 or above.",
"wallet.send.trezor.error.noWitness": "Could not sign the transaction. Please ensure the passphrase you entered is the passhprase used to create this wallet.",
"wallet.settings.blockchain.explorer.title": "Explorer settings",
"wallet.settings.changePassword.dialog.currentPasswordFieldPlaceholder": "Type current password",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow

import { observable, action, reaction } from 'mobx';
import { observable, action, reaction, runInAction } from 'mobx';
import BigNumber from 'bignumber.js';
import Store from '../base/Store';
import LocalizedRequest from '../lib/LocalizedRequest';
Expand All @@ -27,6 +27,8 @@ export default class AdaDelegationTransactionStore extends Store<StoresMap, Acti
/** tracks if wallet balance changed during confirmation screen */
@observable isStale: boolean = false;

@observable error: ?Error = null;

// eslint-disable-next-line no-restricted-syntax
_updateTxBuilderReaction: void => mixed = reaction(
() => [
Expand Down Expand Up @@ -146,45 +148,51 @@ export default class AdaDelegationTransactionStore extends Store<StoresMap, Acti
this.stores.delegation.disablePoolTransitionState(request.wallet);
return this.stores.wallets.refreshWalletFromRemote(request.wallet.publicDeriverId);
};

if (request.wallet.type === 'ledger') {
await this.stores.substores.ada.wallets.adaSendAndRefresh({
broadcastRequest: {
ledger: {
signRequest: result.signTxRequest,
wallet: request.wallet,
try {
if (request.wallet.type === 'ledger') {
await this.stores.substores.ada.wallets.adaSendAndRefresh({
broadcastRequest: {
ledger: {
signRequest: result.signTxRequest,
wallet: request.wallet,
},
},
},
refreshWallet,
});
return;
}
if (request.wallet.type === 'trezor') {
refreshWallet,
});
return;
}
if (request.wallet.type === 'trezor') {
await this.stores.substores.ada.wallets.adaSendAndRefresh({
broadcastRequest: {
trezor: {
signRequest: result.signTxRequest,
wallet: request.wallet,
},
},
refreshWallet,
});
return;
}
// normal password-based wallet
if (request.password == null) {
throw new Error(`${nameof(this._signTransaction)} missing password for non-hardware signing`);
}
await this.stores.substores.ada.wallets.adaSendAndRefresh({
broadcastRequest: {
trezor: {
signRequest: result.signTxRequest,
normal: {
wallet: request.wallet,
password: request.password,
signRequest: result.signTxRequest,
},
},
refreshWallet,
});
return;
}
// normal password-based wallet
if (request.password == null) {
throw new Error(`${nameof(this._signTransaction)} missing password for non-hardware signing`);
} catch (error) {
runInAction(() => {
this.error = error;
});
throw error;
}
await this.stores.substores.ada.wallets.adaSendAndRefresh({
broadcastRequest: {
normal: {
wallet: request.wallet,
password: request.password,
signRequest: result.signTxRequest,
},
},
refreshWallet,
});
if (request.dialog) this.actions.dialogs.open.trigger({ dialog: request.dialog });
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const allCategoriesRevamp: Array<SidebarCategoryRevamp> = [
route: '/governance',
icon: governanceIcon,
label: globalMessages.sidebarGovernance,
isVisible: ({ selected }) => selected != null && selected.type !== 'trezor',
isVisible: ({ selected }) => selected != null,
},
{
className: 'settings',
Expand Down
2 changes: 1 addition & 1 deletion packages/yoroi-extension/chrome/manifest-mv2.template.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default ({
],
content_scripts: [
{
matches: ['*://connect.trezor.io/*/popup.html'],
matches: ['*://connect.trezor.io/*/popup.html*'],
js: ['js/trezor-content-script.js'],
},
],
Expand Down
2 changes: 1 addition & 1 deletion packages/yoroi-extension/chrome/manifest.template.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default ({
],
content_scripts: [
{
matches: ['*://connect.trezor.io/*/popup.html'],
matches: ['*://connect.trezor.io/*/popup.html*'],
js: ['js/trezor-content-script.js'],
},
],
Expand Down
Loading
Loading