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

Tim/eng 3475 nonce not updating correctly after switching accounts #725

Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion src/app/components/transactionSetting/editNonce.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function EditNonce({ nonce, setNonce }: Props) {

useEffect(() => {
setNonce(nonceInput);
}, [nonceInput]);
}, [nonceInput, setNonce]);

return (
<NonceContainer>
Expand Down
1 change: 1 addition & 0 deletions src/app/hooks/queries/useStxWalletData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useDispatch } from 'react-redux';
import useNetworkSelector from '../useNetwork';
import useWalletSelector from '../useWalletSelector';

// TODO refactor: no need to put this in store. use this hook instead
export const useStxWalletData = () => {
const dispatch = useDispatch();
const { stxAddress } = useWalletSelector();
Expand Down
107 changes: 59 additions & 48 deletions src/app/screens/transactionRequest/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import useStxTransactionRequest from '@hooks/useStxTransactionRequest';
import useWalletReducer from '@hooks/useWalletReducer';
import useWalletSelector from '@hooks/useWalletSelector';
import {
Account,
buf2hex,
Coin,
ContractFunction,
Expand All @@ -18,6 +19,7 @@ import { ContractCallPayload, ContractDeployPayload } from '@stacks/connect';
import { StacksTransaction } from '@stacks/transactions';
import { getNetworkType, isHardwareAccount } from '@utils/helper';
import { useEffect, useState } from 'react';
import toast from 'react-hot-toast';
import { useNavigate } from 'react-router-dom';
import { MoonLoader } from 'react-spinners';
import styled from 'styled-components';
Expand All @@ -42,16 +44,15 @@ function TransactionRequest() {
const [coinsMetaData, setCoinsMetaData] = useState<Coin[] | null>(null);
const [codeBody, setCodeBody] = useState(undefined);
const [contractName, setContractName] = useState(undefined);
const [hasSwitchedAccount, setHasSwitchedAccount] = useState(false);
const [attachment, setAttachment] = useState<Buffer | undefined>(undefined);

const handleTokenTransferRequest = async (tokenTransferPayload: any) => {
const handleTokenTransferRequest = async (tokenTransferPayload: any, requestAccount: Account) => {
const stxPendingTxData = await fetchStxPendingTxData(stxAddress, selectedNetwork);
const unsignedSendStxTx = await getTokenTransferRequest(
tokenTransferPayload.recipient,
tokenTransferPayload.amount,
tokenTransferPayload.memo!,
stxPublicKey,
requestAccount.stxPublicKey,
feeMultipliers!,
selectedNetwork,
stxPendingTxData || [],
Expand All @@ -69,16 +70,19 @@ function TransactionRequest() {
});
};

const handleContractCallRequest = async (contractCallPayload: ContractCallPayload) => {
const handleContractCallRequest = async (
contractCallPayload: ContractCallPayload,
requestAccount: Account,
) => {
const {
unSignedContractCall,
contractInterface,
coinsMetaData: coinMeta,
} = await getContractCallPromises(
contractCallPayload,
stxAddress,
requestAccount.stxAddress,
selectedNetwork,
stxPublicKey,
requestAccount.stxPublicKey,
stacksTransaction?.auth,
);
setUnsignedTx(unSignedContractCall);
Expand All @@ -104,21 +108,61 @@ function TransactionRequest() {
}
};

const handleContractDeployRequest = async (contractDeployPayload: ContractDeployPayload) => {
const handleContractDeployRequest = async (
contractDeployPayload: ContractDeployPayload,
requestAccount: Account,
) => {
const response = await createDeployContractRequest(
contractDeployPayload,
selectedNetwork,
stxPublicKey,
requestAccount.stxPublicKey,
feeMultipliers!,
m-aboelenein marked this conversation as resolved.
Show resolved Hide resolved
stxAddress,
requestAccount.stxAddress,
stacksTransaction?.auth,
);
setUnsignedTx(response.contractDeployTx);
setCodeBody(response.codeBody);
setContractName(response.contractName);
};

const switchAccountBasedOnRequest = () => {
const handleTxSigningRequest = async (requestAccount: Account) => {
if (payload.txType === 'contract_call') {
await handleContractCallRequest(payload, requestAccount);
} else if (payload.txType === 'smart_contract') {
await handleContractDeployRequest(payload, requestAccount);
} else {
navigate('/confirm-stx-tx', {
state: {
unsignedTx: payload.txHex,
sponsored: payload.sponsored,
isBrowserTx: true,
tabId,
requestToken,
},
});
}
};

const createRequestTx = async (account: Account) => {
try {
if (!payload.txHex) {
if (payload.txType === 'token_transfer') {
await handleTokenTransferRequest(payload, account);
} else if (payload.txType === 'contract_call') {
await handleContractCallRequest(payload, account);
} else if (payload.txType === 'smart_contract') {
await handleContractDeployRequest(payload, account);
}
} else {
await handleTxSigningRequest(account);
}
} catch (e: unknown) {
console.error(e); // eslint-disable-line
toast.error('Unexpected error creating transaction');
}
};

const handleRequest = async () => {
if (getNetworkType(payload.network) !== network.type) {
navigate('/tx-status', {
state: {
Expand All @@ -134,7 +178,8 @@ function TransactionRequest() {
if (payload.stxAddress !== selectedAccount?.stxAddress && !isHardwareAccount(selectedAccount)) {
const account = accountsList.find((acc) => acc.stxAddress === payload.stxAddress);
if (account) {
switchAccount(account);
await switchAccount(account);
await createRequestTx(account);
} else {
navigate('/tx-status', {
state: {
Expand All @@ -146,48 +191,14 @@ function TransactionRequest() {
},
});
}
}
setHasSwitchedAccount(true);
};

const handleTxSigningRequest = async () => {
if (payload.txType === 'contract_call') {
await handleContractCallRequest(payload);
} else if (payload.txType === 'smart_contract') {
await handleContractDeployRequest(payload);
} else {
navigate('/confirm-stx-tx', {
state: {
unsignedTx: payload.txHex,
sponsored: payload.sponsored,
isBrowserTx: true,
tabId,
requestToken,
},
});
}
};

const createRequestTx = async () => {
if (hasSwitchedAccount) {
if (!payload.txHex) {
if (payload.txType === 'token_transfer') {
await handleTokenTransferRequest(payload);
} else if (payload.txType === 'contract_call') {
await handleContractCallRequest(payload);
} else if (payload.txType === 'smart_contract') {
await handleContractDeployRequest(payload);
}
} else {
await handleTxSigningRequest();
}
await createRequestTx(selectedAccount!);
m-aboelenein marked this conversation as resolved.
Show resolved Hide resolved
}
};

useEffect(() => {
switchAccountBasedOnRequest();
createRequestTx();
}, [hasSwitchedAccount]);
handleRequest();
}, []);

return (
<>
Expand Down
31 changes: 31 additions & 0 deletions src/app/stores/wallet/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,37 @@ import {
WalletState,
} from './actions/types';

/*
* This store should ONLY be used for global app settings such as:
* - hasActivatedOrdinalsKey: undefined,
* - hasActivatedRareSatsKey: undefined,
* - hasActivatedRBFKey: true,
* - rareSatsNoticeDismissed: undefined,
* - showBtcReceiveAlert: true,
* - showOrdinalReceiveAlert: true,
* - showDataCollectionAlert: true,
* - btcApiUrl: '',
* - selectedAccount: null,
* - accountType: 'software',
* - accountName: undefined,
* - walletLockPeriod: WalletSessionPeriods.STANDARD,
* - isUnlocked: false,
* - fiatCurrency: 'USD',
*
* because we get many bugs around caching the wrong values when switching accounts,
* we prefer react-query cache (with the correct cache keys) for all
* account-specific values, and API fetch results such as:
* - btcFiatRate: '0',
* - stxBtcRate: '0',
* - stxBalance: '0',
* - stxAvailableBalance: '0',
* - stxLockedBalance: '0',
* - stxNonce: 0,
* - btcBalance: '0',
* - feeMultipliers: null,
*
* TODO refactor most of these values out of the store and use query cache instead
*/
const initialWalletState: WalletState = {
stxAddress: '',
btcAddress: '',
Expand Down