Skip to content

Commit

Permalink
chore(wallet-core): separate ethereum nonce calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
martykan committed Feb 12, 2025
1 parent ef5d0dd commit 91ffe0b
Showing 1 changed file with 43 additions and 24 deletions.
67 changes: 43 additions & 24 deletions suite-common/wallet-core/src/send/sendFormEthereumThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import {
STAKE_GAS_LIMIT_RESERVE,
} from '@suite-common/wallet-constants';
import {
Account,
AddressDisplayOptions,
ExternalOutput,
PrecomposedLevels,
PrecomposedTransaction,
RbfTransactionParams,
} from '@suite-common/wallet-types';
import {
amountToSmallestUnit,
Expand Down Expand Up @@ -256,6 +258,40 @@ export const composeEthereumTransactionFeeLevelsThunk = createThunk<
},
);

export const ethereumGetCurrentNonceThunk = createThunk<
{ nonce: string },
{ selectedAccount: Account & { networkType: 'ethereum' }; rbfParams?: RbfTransactionParams }
>(
`${SEND_MODULE_PREFIX}/ethereumGetCurrentNonceThunk`,
({ selectedAccount, rbfParams }, { getState }) => {
// Ethereum account `misc.nonce` is not updated before pending tx is mined
// Calculate `pendingNonce`: greatest value in pending tx + 1
// This may lead to unexpected/unwanted behavior
// whenever pending tx gets rejected all following txs (with higher nonce) will be rejected as well
const transactions = selectTransactions(getState());
const pendingTxs = (transactions[selectedAccount.key] || []).filter(isPending);
const pendingNonce = pendingTxs.reduce((value, tx) => {
if (!tx.ethereumSpecific) return value;

return Math.max(value, tx.ethereumSpecific.nonce + 1);
}, 0);

const pendingNonceBig = new BigNumber(pendingNonce);
const accountNonce = selectedAccount.misc?.nonce;

let nonce =
pendingNonceBig.gt(0) && pendingNonceBig.gt(accountNonce)
? pendingNonceBig.toString()
: accountNonce;

if (rbfParams && typeof rbfParams.ethereumNonce === 'number') {
nonce = rbfParams.ethereumNonce.toString();
}

return { nonce };
},
);

export const signEthereumSendFormTransactionThunk = createThunk<
{ serializedTx: string },
SignTransactionThunkArguments,
Expand All @@ -264,12 +300,11 @@ export const signEthereumSendFormTransactionThunk = createThunk<
`${SEND_MODULE_PREFIX}/signEthereumSendFormTransactionThunk`,
async (
{ formState, precomposedTransaction, selectedAccount, device },
{ getState, extra, rejectWithValue },
{ dispatch, getState, extra, rejectWithValue },
) => {
const {
selectors: { selectAddressDisplayType },
} = extra;
const transactions = selectTransactions(getState());

const network = getNetwork(selectedAccount.symbol);

Expand All @@ -281,28 +316,12 @@ export const signEthereumSendFormTransactionThunk = createThunk<

const addressDisplayType = selectAddressDisplayType(getState());

// Ethereum account `misc.nonce` is not updated before pending tx is mined
// Calculate `pendingNonce`: greatest value in pending tx + 1
// This may lead to unexpected/unwanted behavior
// whenever pending tx gets rejected all following txs (with higher nonce) will be rejected as well
const pendingTxs = (transactions[selectedAccount.key] || []).filter(isPending);
const pendingNonce = pendingTxs.reduce((value, tx) => {
if (!tx.ethereumSpecific) return value;

return Math.max(value, tx.ethereumSpecific.nonce + 1);
}, 0);

const pendingNonceBig = new BigNumber(pendingNonce);
const accountNonce = selectedAccount.misc?.nonce;

let nonce =
pendingNonceBig.gt(0) && pendingNonceBig.gt(accountNonce)
? pendingNonceBig.toString()
: accountNonce;

if (formState.rbfParams && typeof formState.rbfParams.ethereumNonce === 'number') {
nonce = formState.rbfParams.ethereumNonce.toString();
}
const { nonce } = await dispatch(
ethereumGetCurrentNonceThunk({
selectedAccount,
rbfParams: formState.rbfParams,
}),
).unwrap();

// transform to TrezorConnect.ethereumSignTransaction params
const transaction = prepareEthereumTransaction({
Expand Down

0 comments on commit 91ffe0b

Please sign in to comment.