* building send and replace settings context * adding translations * fixing double parse * adding spend and replace flags to send txs * adding listener to handle sar payments * add tx descripion handler for sar payments in restore * making sure sar key is fetched during app load * split toast manager and toast continer * adding tests * adding custom sar payment title to toast message * removing spark sdk navigation * adding sarPayment mark to transaction table * pass poolInfoRef from context to remove fetch if value is already set * remove spark naviagtion listener * fix btc -> usd swaps not calling sar * finalize spend and replace * fix timeout mismatch * adding usablePaymentMethod to narrow eligiblility * block requsets if account switches * remove duplicate storage and keep all referances to keyscontext * steralize writes to fix overlap issue
124 lines
3.8 KiB
JavaScript
124 lines
3.8 KiB
JavaScript
import { useEffect, createContext, useRef } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import {
|
|
sparkTransactionsEventEmitter,
|
|
SPARK_TX_UPDATE_ENVENT_NAME,
|
|
ensureSparkDatabaseReady,
|
|
} from '../app/functions/spark/transactions';
|
|
import { SPEND_AND_REPLACE_STORAGE_KEY } from '../app/constants';
|
|
import { useGlobalContextProvider } from './context';
|
|
import { useSparkWallet } from './sparkContext';
|
|
import { useKeysContext } from './keys';
|
|
import { processSpendAndReplaceIntents } from '../app/functions/spark/spendAndReplace';
|
|
import { useFlashnet } from './flashnetContext';
|
|
|
|
const SpendAndReplaceContext = createContext(null);
|
|
|
|
export function SpendAndReplaceProvider({ children }) {
|
|
const { masterInfoObject } = useGlobalContextProvider();
|
|
const { sparkInformation } = useSparkWallet();
|
|
const { accountMnemoinc } = useKeysContext();
|
|
const { t } = useTranslation();
|
|
const { poolInfoRef } = useFlashnet();
|
|
const isProcessingRef = useRef(false);
|
|
const needsRerunRef = useRef(false);
|
|
const latestAccountRef = useRef({
|
|
accountId: '',
|
|
sparkAddress: '',
|
|
mnemonic: '',
|
|
});
|
|
|
|
useEffect(() => {
|
|
latestAccountRef.current = {
|
|
accountId: sparkInformation?.identityPubKey || '',
|
|
sparkAddress: sparkInformation?.sparkAddress || '',
|
|
mnemonic: accountMnemoinc || '',
|
|
};
|
|
}, [
|
|
sparkInformation?.identityPubKey,
|
|
sparkInformation?.sparkAddress,
|
|
accountMnemoinc,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
const handleTransactionUpdate = async () => {
|
|
if (!masterInfoObject[SPEND_AND_REPLACE_STORAGE_KEY]?.isEnabled) return;
|
|
|
|
const accountSnapshot = {
|
|
accountId: sparkInformation?.identityPubKey || '',
|
|
sparkAddress: sparkInformation?.sparkAddress || '',
|
|
mnemonic: accountMnemoinc || '',
|
|
};
|
|
if (
|
|
!accountSnapshot.accountId ||
|
|
!accountSnapshot.sparkAddress ||
|
|
!accountSnapshot.mnemonic
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const isSameActiveAccount = () => {
|
|
const latestAccount = latestAccountRef.current;
|
|
return (
|
|
latestAccount.accountId === accountSnapshot.accountId &&
|
|
latestAccount.sparkAddress === accountSnapshot.sparkAddress &&
|
|
latestAccount.mnemonic === accountSnapshot.mnemonic
|
|
);
|
|
};
|
|
|
|
if (!isSameActiveAccount()) return;
|
|
|
|
if (isProcessingRef.current) {
|
|
needsRerunRef.current = true;
|
|
return;
|
|
}
|
|
isProcessingRef.current = true;
|
|
|
|
try {
|
|
// Drain loop: rerun while events landed mid-pass, until a pass finds no
|
|
// freshly-claimable rows.
|
|
do {
|
|
needsRerunRef.current = false;
|
|
if (!isSameActiveAccount()) return;
|
|
const db = await ensureSparkDatabaseReady();
|
|
await processSpendAndReplaceIntents({
|
|
db,
|
|
accountId: accountSnapshot.accountId,
|
|
mnemonic: accountSnapshot.mnemonic,
|
|
sparkAddress: accountSnapshot.sparkAddress,
|
|
t,
|
|
poolInfoRef,
|
|
isSameActiveAccount,
|
|
});
|
|
} while (needsRerunRef.current && isSameActiveAccount());
|
|
} catch (err) {
|
|
console.error('SpendAndReplace handler error:', err);
|
|
} finally {
|
|
isProcessingRef.current = false;
|
|
}
|
|
};
|
|
|
|
sparkTransactionsEventEmitter.on(
|
|
SPARK_TX_UPDATE_ENVENT_NAME,
|
|
handleTransactionUpdate,
|
|
);
|
|
|
|
// Run once on mount to resume payments that confirmed while the app was
|
|
// closed (discovered as unclaimed on next launch).
|
|
handleTransactionUpdate();
|
|
|
|
return () => {
|
|
sparkTransactionsEventEmitter.off(
|
|
SPARK_TX_UPDATE_ENVENT_NAME,
|
|
handleTransactionUpdate,
|
|
);
|
|
};
|
|
}, [masterInfoObject, sparkInformation, accountMnemoinc, t]);
|
|
|
|
return (
|
|
<SpendAndReplaceContext.Provider value={null}>
|
|
{children}
|
|
</SpendAndReplaceContext.Provider>
|
|
);
|
|
}
|