Skip to content

Commit

Permalink
refactor(suite): redundant precomposedForm state removed from sendFor…
Browse files Browse the repository at this point in the history
…m reducer
  • Loading branch information
PeKne committed May 29, 2024
1 parent 1eef2ef commit 8631fda
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 196 deletions.
183 changes: 89 additions & 94 deletions packages/suite/src/actions/wallet/send/sendFormThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
pushSendFormTransactionThunk,
replaceTransactionThunk,
selectDevice,
selectPrecomposedSendForm,
selectSendFormDrafts,
signTransactionThunk,
sendFormActions,
selectSendFormDraftByAccountKey,
} from '@suite-common/wallet-core';
import { isCardanoTx } from '@suite-common/wallet-utils';
import { MetadataAddPayload } from '@suite-common/metadata-types';
Expand All @@ -28,7 +28,7 @@ import {
selectSelectedAccountKey,
selectIsSelectedAccountLoaded,
} from 'src/reducers/wallet/selectedAccountReducer';
import { findLabelsToBeMovedOrDeleted } from '../moveLabelsForRbfActions';
import { findLabelsToBeMovedOrDeleted, moveLabelsForRbfAction } from '../moveLabelsForRbfActions';
import { selectMetadata } from 'src/reducers/suite/metadataReducer';
import * as metadataLabelingActions from 'src/actions/suite/metadataLabelingActions';
import * as modalActions from 'src/actions/suite/modalActions';
Expand Down Expand Up @@ -95,19 +95,15 @@ const updateRbfLabelsThunk = createThunk(
(
{
labelsToBeEdited,
precomposedTx,
precomposedTransaction,
txid,
}: {
labelsToBeEdited: RbfLabelsToBeUpdated;
precomposedTx: PrecomposedTransactionFinal;
precomposedTransaction: PrecomposedTransactionFinal;
txid: string;
},
{ dispatch, extra },
{ dispatch },
) => {
const {
thunks: { moveLabelsForRbfAction },
} = extra;

dispatch(
moveLabelsForRbfAction({
toBeMovedOrDeletedList: labelsToBeEdited,
Expand All @@ -120,7 +116,7 @@ const updateRbfLabelsThunk = createThunk(
// this will update transaction details (like time, fee etc.)
dispatch(
replaceTransactionThunk({
precomposedTx,
precomposedTransaction,
newTxid: txid,
}),
);
Expand All @@ -132,63 +128,61 @@ const applySendFormMetadataLabelsThunk = createThunk(
(
{
selectedAccount,
precomposedTx,
precomposedTransaction,
txid,
}: {
selectedAccount: Account;
precomposedTx: GeneralPrecomposedTransactionFinal;
precomposedTransaction: GeneralPrecomposedTransactionFinal;
txid: string;
},
{ dispatch, getState },
) => {
const metadata = selectMetadata(getState());
if (metadata.enabled) {
const precomposedForm = selectPrecomposedSendForm(getState());
let outputsPermutation: number[];
if (isCardanoTx(selectedAccount, precomposedTx)) {
// cardano preserves order of outputs
outputsPermutation = precomposedTx?.outputs.map((_o, i) => i);
} else {
outputsPermutation = precomposedTx?.outputsPermutation;
}

const synchronize = getSynchronize();

precomposedForm?.outputs
// create array of metadata objects
.map((formOutput, index) => {
const { label } = formOutput;
// final ordering of outputs differs from order in send form
// outputsPermutation contains mapping from @trezor/utxo-lib outputs to send form outputs
// mapping goes like this: Array<@trezor/utxo-lib index : send form index>
const outputIndex = outputsPermutation.findIndex(p => p === index);
const outputMetadata: Extract<MetadataAddPayload, { type: 'outputLabel' }> = {
type: 'outputLabel',
entityKey: selectedAccount.key,
txid,
outputIndex,
value: label,
defaultValue: '',
};

return outputMetadata;
})
// filter out empty values AFTER creating metadata objects (see outputs mapping above)
.filter(output => output.value)
// propagate metadata to reducers and persistent storage
.forEach((output, index, arr) => {
const isLast = index === arr.length - 1;

synchronize(() =>
dispatch(
metadataLabelingActions.addAccountMetadata({
...output,
skipSave: !isLast,
}),
),
);
});
}

if (!metadata.enabled) return;

const formDraft = selectSendFormDraftByAccountKey(getState(), selectedAccount.key);

const outputsPermutation = isCardanoTx(selectedAccount, precomposedTransaction)
? precomposedTransaction?.outputs.map((_o, i) => i) // cardano preserves order of outputs
: precomposedTransaction?.outputsPermutation;

const synchronize = getSynchronize();

formDraft?.outputs
// create array of metadata objects
.map((formOutput, index) => {
const { label } = formOutput;
// final ordering of outputs differs from order in send form
// outputsPermutation contains mapping from @trezor/utxo-lib outputs to send form outputs
// mapping goes like this: Array<@trezor/utxo-lib index : send form index>
const outputIndex = outputsPermutation.findIndex(p => p === index);
const outputMetadata: Extract<MetadataAddPayload, { type: 'outputLabel' }> = {
type: 'outputLabel',
entityKey: selectedAccount.key,
txid,
outputIndex,
value: label,
defaultValue: '',
};

return outputMetadata;
})
// filter out empty values AFTER creating metadata objects (see outputs mapping above)
.filter(output => output.value)
// propagate metadata to reducers and persistent storage
.forEach((output, index, arr) => {
const isLast = index === arr.length - 1;

synchronize(() =>
dispatch(
metadataLabelingActions.addAccountMetadata({
...output,
skipSave: !isLast,
}),
),
);
});
},
);

Expand Down Expand Up @@ -241,49 +235,50 @@ export const signAndPushSendFormTransactionThunk = createThunk(
const isPushConfirmed = await dispatch(
modalActions.openDeferredModal({ type: 'review-transaction' }),
);
if (isPushConfirmed) {
const isRbf = precomposedTransaction.prevTxid !== undefined;

// This has to be executed prior to pushing the transaction!
const rbfLabelsToBeEdited = isRbf
? dispatch(
findLabelsToBeMovedOrDeleted({ prevTxid: precomposedTransaction.prevTxid }),
)
: null;

// push tx to the network
const pushResponse = await dispatch(
pushSendFormTransactionThunk({
selectedAccount,
}),
);

if (isRejected(pushResponse)) {
return pushResponse.payload as Unsuccessful;
}
if (!isPushConfirmed) {
return;
}

const result = pushResponse.payload;
const { txid } = result.payload;
const isRbf = precomposedTransaction.prevTxid !== undefined;

if (isRbf && rbfLabelsToBeEdited) {
await dispatch(
updateRbfLabelsThunk({
labelsToBeEdited: rbfLabelsToBeEdited,
precomposedTx: precomposedTransaction,
txid,
}),
);
}
// This has to be executed prior to pushing the transaction!
const rbfLabelsToBeEdited = isRbf
? dispatch(findLabelsToBeMovedOrDeleted({ prevTxid: precomposedTransaction.prevTxid }))
: null;

// push tx to the network
const pushResponse = await dispatch(
pushSendFormTransactionThunk({
selectedAccount,
}),
);

if (isRejected(pushResponse)) {
return pushResponse.payload as Unsuccessful;
}

const result = pushResponse.payload;
const { txid } = result.payload;

if (isRbf && rbfLabelsToBeEdited) {
dispatch(
applySendFormMetadataLabelsThunk({
selectedAccount,
precomposedTx: precomposedTransaction,
updateRbfLabelsThunk({
labelsToBeEdited: rbfLabelsToBeEdited,
precomposedTransaction,
txid,
}),
);

return result;
}

dispatch(
applySendFormMetadataLabelsThunk({
selectedAccount,
precomposedTransaction,
txid,
}),
);

return result;
},
);
2 changes: 1 addition & 1 deletion packages/suite/src/actions/wallet/stakeActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const pushTransaction =
// this will update transaction details (like time, fee etc.)
dispatch(
replaceTransactionThunk({
precomposedTx,
precomposedTransaction: precomposedTx,
newTxid: txid,
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled from 'styled-components';
import { ConfirmOnDevice, variables } from '@trezor/components';
import { Deferred } from '@trezor/utils';
import { selectDevice, StakeState } from '@suite-common/wallet-core';
import { FormState, StakeFormState } from '@suite-common/wallet-types';
import { isCardanoTx } from '@suite-common/wallet-utils';
import { SendState } from '@suite-common/wallet-core';
import { useSelector } from 'src/hooks/suite';
Expand All @@ -28,6 +29,14 @@ const StyledModal = styled(Modal)`
}
`;

const isStakeState = (state: SendState | StakeState): state is StakeState => {
return 'data' in state;
};

const isStakeForm = (form: FormState | StakeFormState): form is StakeFormState => {
return 'ethereumStakeType' in form;
};

interface TransactionReviewModalContentProps {
decision: Deferred<boolean, string | number | undefined> | undefined;
txInfoState: SendState | StakeState;
Expand All @@ -48,13 +57,21 @@ export const TransactionReviewModalContent = ({

const deviceModelInternal = device?.features?.internal_model;

const { precomposedTx, precomposedForm, serializedTx } = txInfoState;
const { account } = selectedAccount;
const { precomposedTx, serializedTx } = txInfoState;

if (!account) {
return null;
}

const precomposedForm: FormState | StakeFormState | undefined = isStakeState(txInfoState)
? txInfoState.precomposedForm
: txInfoState.drafts[account.key];

if (selectedAccount.status !== 'loaded' || !device || !precomposedTx || !precomposedForm) {
return null;
}

const { account } = selectedAccount;
const { networkType } = account;
const isCardano = isCardanoTx(account, precomposedTx);
const isEthereum = networkType === 'ethereum';
Expand All @@ -71,8 +88,9 @@ export const TransactionReviewModalContent = ({
precomposedTx,
});

const ethereumStakeType =
'ethereumStakeType' in precomposedForm ? precomposedForm.ethereumStakeType : null;
const ethereumStakeType = isStakeForm(precomposedForm)
? precomposedForm.ethereumStakeType
: null;

// omit other button requests (like passphrase)
const buttonRequests = device.buttonRequests.filter(
Expand Down
6 changes: 3 additions & 3 deletions packages/suite/src/hooks/wallet/form/useCompose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,16 +231,16 @@ export const useCompose = <TFieldValues extends FormState>({
// called from the UI, triggers signing process
const sign = async () => {
const values = getValues();
const composedTx = composedLevels
const precomposedTransaction = composedLevels
? composedLevels[values.selectedFee || 'normal']
: undefined;
if (composedTx && composedTx.type === 'final') {
if (precomposedTransaction && precomposedTransaction.type === 'final') {
// sign workflow in Actions:
// signSendFormTransactionThunk > sign[COIN]TransactionThunk > sendFormActions.storeSignedTransaction (modal with promise decision)
const result = await dispatch(
signAndPushSendFormTransactionThunk({
formValues: values,
precomposedTransaction: composedTx,
precomposedTransaction,
selectedAccount,
}),
).unwrap();
Expand Down
6 changes: 5 additions & 1 deletion packages/suite/src/hooks/wallet/useCardanoStaking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,11 @@ export const useCardanoStaking = (): CardanoStaking => {
}),
);
dispatch(
addFakePendingCardanoTxThunk({ precomposedTx: txPlan, txid, account }),
addFakePendingCardanoTxThunk({
precomposedTransaction: txPlan,
txid,
account,
}),
);
dispatch(setPendingStakeTx(account, txid));
} else {
Expand Down
12 changes: 6 additions & 6 deletions packages/suite/src/hooks/wallet/useCoinmarketRecomposeAndSign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,14 @@ export const useCoinmarketRecomposeAndSign = () => {

return;
}
const composedToSign = composedLevels[selectedFee];
const precomposedToSign = composedLevels[selectedFee];

if (!composedToSign || composedToSign.type !== 'final') {
if (!precomposedToSign || precomposedToSign.type !== 'final') {
let errorMessage: string | undefined;
if (composedToSign?.type === 'error' && composedToSign.errorMessage) {
if (precomposedToSign?.type === 'error' && precomposedToSign.errorMessage) {
errorMessage = translationString(
composedToSign.errorMessage.id,
composedToSign.errorMessage.values as { [key: string]: any },
precomposedToSign.errorMessage.id,
precomposedToSign.errorMessage.values as { [key: string]: any },
);
}
if (!errorMessage) {
Expand All @@ -149,7 +149,7 @@ export const useCoinmarketRecomposeAndSign = () => {
return dispatch(
signAndPushSendFormTransactionThunk({
formValues,
precomposedTransaction: composedToSign,
precomposedTransaction: precomposedToSign,
selectedAccount: account,
}),
).unwrap();
Expand Down

0 comments on commit 8631fda

Please sign in to comment.