diff --git a/app/src/RollupWallet.tsx b/app/src/RollupWallet.tsx index 0302e565..4d0aa837 100644 --- a/app/src/RollupWallet.tsx +++ b/app/src/RollupWallet.tsx @@ -38,7 +38,7 @@ import {WalletBrand,WalletHeaderActions} from './WalletHeaderActions.tsx'; import {WalletCreatedNotice,WalletSecurityMenu,type WalletSecurityView} from './WalletSecurityMenu.tsx'; import {isNativeHost,nativeClaimFetch,nativeOperationFetch,nativeSessionFetch,nativeSwapConfig,nativeWalletProviders} from '../../src/native/index.ts'; import {loadWalletPoseidon} from './wallet-crypto.ts'; -import {pendingPoolNullifiers,pendingPoolOutpoints,reconcileNativeJournal} from '../../src/native/mutations.ts'; +import {forceReleaseNativeJournal,pendingPoolNullifiers,pendingPoolOutpoints,reconcileNativeJournal} from '../../src/native/mutations.ts'; import {privateTransport,PRIVATE_SHIELD_COINS} from '../../src/shielded/private-transport.ts'; import {PRIVATE_FLAG} from './private-boot.ts'; @@ -89,7 +89,7 @@ const focusOnMount=(el:HTMLElement|null)=>{el?.focus();}; export default function RollupWallet({storage=globalThis.localStorage,reload=()=>location.reload(),onShutdown,onReady,onStartupFailure,onStartupStage,onClearWallet,nativeHost=INJECTED_NATIVE,paymentRequest,onPaymentRequestHandled,onResumeSnapshot,onScannerIntentChange,resumeScanner,onResumeScannerHandled,animateEntrance=true,suspended=false,viewActive=true,hidden=false}:{storage?:Storage;reload?:()=>void;onShutdown?:(shutdown:(()=>Promise)|undefined)=>void;onReady?:()=>void;onStartupFailure?:(message:string)=>void;onStartupStage?:(message:string)=>void;onClearWallet?:()=>Promise;nativeHost?:boolean;paymentRequest?:IncomingPayment;onPaymentRequestHandled?:(id:number)=>void;onResumeSnapshot?:(snapshot:NativeResumeSnapshot)=>void;onScannerIntentChange?:(requested:boolean)=>void;resumeScanner?:number;onResumeScannerHandled?:(token:number)=>void;animateEntrance?:boolean;suspended?:boolean;viewActive?:boolean;hidden?:boolean}={}){ const [sessionFetch]=useState(()=>nativeHost?nativeSessionFetch():undefined); const [pool,setPool]=useState(),[poolError,setPoolError]=useState(''),[journalError,setJournalError]=useState(''); - const [nativePending,setNativePending]=useState(false); + const [nativePending,setNativePending]=useState(false),[confirmRelease,setConfirmRelease]=useState(false),[releaseNote,setReleaseNote]=useState(''); const [startupError,setStartupError]=useState(''),[startupFailure,setStartupFailure]=useState(''),[refreshError,setRefreshError]=useState(''),[feeNotice,setFeeNotice]=useState(''),[feeConfirmed,setFeeConfirmed]=useState(false); const [startupStage,setStartupStage]=useState('Preparing your private wallet'); const [initialPool,setInitialPool]=useState(); @@ -473,6 +473,16 @@ export default function RollupWallet({storage=globalThis.localStorage,reload=()= .then(pending=>{if(live){setNativePending(pending);setJournalError('');}},error=>{if(live){setNativePending(true);setJournalError(errorText(error));}}); return()=>{live=false;}; },[wallet,tick,nativeHost,sessionFetch]); + const releaseReserved=()=>{ + setConfirmRelease(false); + try{ + const {released,payments,waiting}=nativeHost?forceReleaseNativeJournal(POOL_ORIGIN):PRIVATE!.journal.forceRelease(PRIVATE!.poolOrigin); + setReleaseNote([released?`Released ${released===1?'one reserved shield':`${released} reserved shields`}.`:'No shield was released.', + waiting?'A shield sent in the last 15 minutes stays reserved while it may still reach the pool.':'', + payments?'A payment stays reserved until this wallet can prove the pool will not include it, which it rechecks every minute.':''].filter(Boolean).join(' ')); + setTick(t=>t+1); + }catch(error){setJournalError(errorText(error));} + }; useEffect(()=>{lnLimits.current=wallet?.swaps;lnLimitsRead.current++;setLnBounds(undefined);setLnBoundsError('');},[wallet,wallet?.swaps]); // markets() must load the snapshot before resolve() reads it. const readLnBounds=()=>{ @@ -738,7 +748,11 @@ export default function RollupWallet({storage=globalThis.localStorage,reload=()= const inactive=hidden||suspended||!viewActive; if(!secret||!wallet)return ; return