import { atom } from 'jotai' ; import { atomFamily , atomWithStorage } from 'jotai/utils' ; import deepEqual from 'fast-deep-equal' ; import { currentAccountConfirmedTransactionsState , currentAccountInfoState , currentAccountMempoolTransactionsState , currentAccountStxAddressState , } from '@app/store/accounts' ; import { currentNetworkState } from '@app/store/network/networks' ; import { makeLocalDataKey } from '@app/common/store-utils' ; import { currentAccountLocallySubmittedLatestNonceState } from '@app/store/accounts/account-activity' ; export const localNonceState = atomFamily < [ principal : string , networkUrl : string ] , number , number > ( params => atomWithStorage ( makeLocalDataKey ( [ 'LOCAL_NONCE_STATE' , params ] ) , 0 ) , deepEqual ) ; const currentAccountLocalNonceState = atom ( get => { const network = get ( currentNetworkState ) ; const address = get ( currentAccountStxAddressState ) ; if ( ! address ) return 0 ; return get ( localNonceState ( [ address , network . url ] ) ) ; } ) ; export const lastApiNonceState = atom < { nonce : number ; isMissing ? : boolean ; } | undefined > ( undefined ) ; export const currentAccountNonceState = atom ( get => { const address = get ( currentAccountStxAddressState ) ; const account = get ( currentAccountInfoState ) ; const confirmedTransactions = get ( currentAccountConfirmedTransactionsState ) ; const pendingTransactions = get ( currentAccountMempoolTransactionsState ) ; const lastLocalNonce = get ( currentAccountLocalNonceState ) ; const latestLocallySubmittedNonce = get ( currentAccountLocallySubmittedLatestNonceState ) ; const lastApiNonce = get ( lastApiNonceState ) ; if ( lastApiNonce ) { if ( lastApiNonce . isMissing ) return lastApiNonce . nonce ; if ( typeof latestLocallySubmittedNonce === 'number' && latestLocallySubmittedNonce + 1 > lastApiNonce . nonce ) return latestLocallySubmittedNonce + 1 ; return lastApiNonce . nonce ; } const lastConfirmedTx = confirmedTransactions ?. filter ( tx => tx . sender_address === address ) ?. [ 0 ] ; const latestPendingTx = pendingTransactions ?. filter ( tx => tx . sender_address === address ) ?. [ 0 ] ; const oldestPendingTx = pendingTransactions ?. length ? pendingTransactions ?. filter ( tx => tx . sender_address === address ) ?. [ pendingTransactions ?. length - 1 ] : undefined ; const hasTransactions = ! ! latestPendingTx || ! ! lastConfirmedTx ; if ( ! account ) return 0 ; const hasNonceMismatch = oldestPendingTx && lastConfirmedTx ? oldestPendingTx . nonce > lastConfirmedTx . nonce + 1 : false ; if ( hasNonceMismatch || ! hasTransactions ) return account . nonce ; const pendingNonce = latestPendingTx ?. nonce || 0 ; const lastConfirmedTxNonce = lastConfirmedTx ?. nonce || 0 ; const useLocalNonce = lastLocalNonce > pendingNonce && lastLocalNonce > lastConfirmedTxNonce ; const usePendingNonce = ! useLocalNonce && ( ( lastConfirmedTx && pendingNonce > lastConfirmedTx . nonce ) || pendingNonce + 1 > account . nonce ) ; const useLastTxNonce = hasTransactions && lastConfirmedTx && lastConfirmedTx . nonce + 1 > account . nonce ; const lastConfirmedNonce = useLastTxNonce && lastConfirmedTx ? lastConfirmedTx . nonce + 1 : account . nonce ; return useLocalNonce ? lastLocalNonce : usePendingNonce ? pendingNonce + 1 : lastConfirmedNonce ; } ) ;