Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
24 changes: 17 additions & 7 deletions src/components/ConfidentialPaymentFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export default function ConfidentialPaymentFlow({
const [step, setStep] = useState<Step>("commit");
const [txHash, setTxHash] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [amountsVisible, setAmountsVisible] = useState(false);

useEffect(() => {
if (!publicKey) return;
Expand Down Expand Up @@ -178,15 +179,24 @@ export default function ConfidentialPaymentFlow({
)}

<div>
<label
htmlFor="confidential-amount"
className="block text-sm font-medium text-gray-300 mb-1"
>
Amount (USDC)
</label>
<div className="flex items-center justify-between mb-1">
<label
htmlFor="confidential-amount"
className="block text-sm font-medium text-gray-300"
>
Amount (USDC)
</label>
<button
type="button"
onClick={() => setAmountsVisible((v) => !v)}
className="text-xs font-medium text-indigo-400 hover:text-indigo-300"
>
{amountsVisible ? "Hide amounts" : "Show amounts"}
</button>
</div>
<input
id="confidential-amount"
type="number"
type={amountsVisible ? "number" : "password"}
step="0.0000001"
min="0.0000001"
placeholder="0.00"
Expand Down
17 changes: 7 additions & 10 deletions src/components/UpgradeBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { useEffect, useState } from "react";
import { splitClient } from "@/lib/stellar";

const STORAGE_KEY_PREFIX = "stellarsplit-upgrade-dismissed-";
const DISMISSED_KEY = "split_upgrade_dismissed";

interface UpgradeInfo {
version: string;
Expand All @@ -13,19 +13,17 @@ interface UpgradeInfo {
export default function UpgradeBanner() {
const [upgrade, setUpgrade] = useState<UpgradeInfo | null>(null);
const [mounted, setMounted] = useState(false);
const [dismissed, setDismissed] = useState(false);

useEffect(() => {
setMounted(true);
setDismissed(sessionStorage.getItem(DISMISSED_KEY) === "true");

let cleanup: (() => void) | undefined;

try {
cleanup = (splitClient as any).watchContractUpgrade((info: UpgradeInfo) => {
const key = `${STORAGE_KEY_PREFIX}${info.version}`;
const dismissed = localStorage.getItem(key) === "true";
if (!dismissed) {
setUpgrade(info);
}
setUpgrade(info);
});
} catch {
// watchContractUpgrade not available in this environment — silently skip
Expand All @@ -37,12 +35,11 @@ export default function UpgradeBanner() {
}, []);

const dismiss = () => {
if (!upgrade) return;
localStorage.setItem(`${STORAGE_KEY_PREFIX}${upgrade.version}`, "true");
setUpgrade(null);
sessionStorage.setItem(DISMISSED_KEY, "true");
setDismissed(true);
};

if (!mounted || !upgrade) return null;
if (!mounted || !upgrade || dismissed) return null;

const changelogHref = upgrade.changelogUrl ?? "/changelog";

Expand Down
17 changes: 12 additions & 5 deletions src/hooks/useTransactionWithRetry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useRef } from 'react';
import { useCallback, useRef, useState } from 'react';
import { useToast } from '@/contexts/ToastContext';

interface RetryOptions {
Expand All @@ -7,15 +7,18 @@ interface RetryOptions {
retryableStatusCodes?: number[];
}

const MAX_DELAY_MS = 30000;

const DEFAULT_OPTIONS = {
maxRetries: 3,
initialDelayMs: 3000,
maxRetries: 5,
initialDelayMs: 1000,
retryableStatusCodes: [429],
};

export function useTransactionWithRetry(options?: RetryOptions) {
const toast = useToast();
const abortControllers = useRef<Map<string, AbortController>>(new Map());
const [attemptCount, setAttemptCount] = useState(0);
const opts = { ...DEFAULT_OPTIONS, ...options };

const getStatusCode = (error: any): number | undefined => {
Expand Down Expand Up @@ -48,6 +51,7 @@ export function useTransactionWithRetry(options?: RetryOptions) {
let toastId: string | null = null;

for (let attempt = 1; attempt <= opts.maxRetries; attempt++) {
setAttemptCount(attempt);
try {
// Check if user cancelled
if (abortControllers.current.get(operationId)?.signal.aborted) {
Expand All @@ -65,7 +69,10 @@ export function useTransactionWithRetry(options?: RetryOptions) {
attempt < opts.maxRetries;

if (isRetryable) {
const delayMs = opts.initialDelayMs * Math.pow(2, attempt - 1);
const delayMs = Math.min(
opts.initialDelayMs * Math.pow(2, attempt - 1),
MAX_DELAY_MS
);
const countdownSeconds = Math.ceil(delayMs / 1000);

// Show countdown toast
Expand Down Expand Up @@ -114,5 +121,5 @@ export function useTransactionWithRetry(options?: RetryOptions) {
}
}, []);

return { executeWithRetry, cancel };
return { executeWithRetry, cancel, attemptCount };
}
Loading