diff --git a/packages/trpc/src/one-click-trading.ts b/packages/trpc/src/one-click-trading.ts
index 53280cc455..b7d164ab8a 100644
--- a/packages/trpc/src/one-click-trading.ts
+++ b/packages/trpc/src/one-click-trading.ts
@@ -33,7 +33,7 @@ export const oneClickTradingRouter = createTRPCRouter({
spendLimitTokenDecimals: usdcAsset.coinDecimals,
networkFeeLimit: OneClickTradingMaxGasLimit,
sessionPeriod: {
- end: "1hour" as const,
+ end: "7days" as const,
},
};
}
diff --git a/packages/types/src/one-click-trading-types.ts b/packages/types/src/one-click-trading-types.ts
index 53741f9e4d..8e92e59816 100644
--- a/packages/types/src/one-click-trading-types.ts
+++ b/packages/types/src/one-click-trading-types.ts
@@ -18,12 +18,10 @@ export interface OneClickTradingTimeLimit {
}
export type OneClickTradingHumanizedSessionPeriod =
- | "5min"
- | "10min"
- | "30min"
| "1hour"
- | "3hours"
- | "12hours";
+ | "1day"
+ | "7days"
+ | "30days";
export interface OneClickTradingTransactionParams {
isOneClickEnabled: boolean;
diff --git a/packages/utils/src/__tests__/date.spec.ts b/packages/utils/src/__tests__/date.spec.ts
new file mode 100644
index 0000000000..3f3bc3a11c
--- /dev/null
+++ b/packages/utils/src/__tests__/date.spec.ts
@@ -0,0 +1,114 @@
+import { safeTimeout } from "../date";
+
+describe("safeTimeout", () => {
+ jest.useFakeTimers(); // Use fake timers for controlled testing
+ jest.spyOn(global, "setTimeout"); // Spy on the setTimeout function
+
+ afterEach(() => {
+ jest.clearAllTimers(); // Clear timers after each test
+ jest.clearAllMocks();
+ });
+
+ test("calls setTimeout directly for time within safe range", () => {
+ const callback = jest.fn();
+ const timeInRange = 5000; // 5 seconds
+
+ safeTimeout(callback, timeInRange);
+
+ // Fast-forward time
+ jest.advanceTimersByTime(timeInRange);
+
+ // Ensure the callback is called once
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), timeInRange);
+ });
+
+ test("splits large timeout into smaller intervals", () => {
+ const callback = jest.fn();
+ const largeTimeout = 2591160000; // 29 days, 23 hours, 46 minutes
+ const MAX_TIMEOUT = 2 ** 31 - 1; // JavaScript's maximum timeout (~24.8 days)
+
+ safeTimeout(callback, largeTimeout);
+
+ // Fast-forward the first interval
+ jest.advanceTimersByTime(MAX_TIMEOUT);
+
+ // Ensure another setTimeout was scheduled for the remainder
+ expect(setTimeout).toHaveBeenCalledTimes(2);
+
+ // Fast-forward the remaining time
+ jest.advanceTimersByTime(largeTimeout - MAX_TIMEOUT);
+
+ // Ensure the callback is called once after both intervals
+ expect(callback).toHaveBeenCalledTimes(1);
+ });
+
+ test("handles exactly the maximum timeout limit", () => {
+ const callback = jest.fn();
+ const exactMaxTimeout = 2 ** 31 - 1;
+
+ safeTimeout(callback, exactMaxTimeout);
+
+ // Fast-forward time
+ jest.advanceTimersByTime(exactMaxTimeout);
+
+ // Ensure the callback is called once
+ expect(callback).toHaveBeenCalledTimes(1);
+ expect(setTimeout).toHaveBeenCalledWith(
+ expect.any(Function),
+ exactMaxTimeout
+ );
+ });
+
+ test("does not call the callback prematurely", () => {
+ const callback = jest.fn();
+ const largeTimeout = 2591160000; // 29 days, 23 hours, 46 minutes
+
+ safeTimeout(callback, largeTimeout);
+
+ // Fast-forward time but do not complete all intervals
+ jest.advanceTimersByTime(2 ** 31 - 2); // Just shy of the max timeout
+
+ // Callback should not be called yet
+ expect(callback).not.toHaveBeenCalled();
+ });
+
+ test("clears the timeout before it completes", () => {
+ const callback = jest.fn(); // Mock callback function
+ const largeTimeout = 2591160000; // ~30 days
+
+ // Set up the safe timeout
+ const { clear } = safeTimeout(callback, largeTimeout);
+
+ // Fast-forward time by 5 seconds and then clear the timeout
+ jest.advanceTimersByTime(5000); // Advance 5 seconds
+ clear(); // Clear the timeout early
+
+ // Advance time further to ensure the callback does not execute
+ jest.advanceTimersByTime(largeTimeout);
+
+ // Verify that the callback was never called
+ expect(callback).not.toHaveBeenCalled();
+ });
+
+ test("clears the second timer in a split timeout chain", () => {
+ const callback = jest.fn(); // Mock callback function
+ const largeTimeout = 2591160000; // ~30 days
+ const MAX_TIMEOUT = 2 ** 31 - 1; // JavaScript's maximum timeout (~24.8 days)
+
+ // Set up the timeout
+ const { clear } = safeTimeout(callback, largeTimeout);
+
+ // Advance time to the end of the first timer but before the second timer finishes
+ jest.advanceTimersByTime(MAX_TIMEOUT);
+
+ // Clear the timeout during the second interval
+ clear();
+
+ // Advance time to simulate the remainder of the second timer
+ jest.advanceTimersByTime(largeTimeout - MAX_TIMEOUT);
+
+ // Verify that the callback was not called
+ expect(callback).not.toHaveBeenCalled();
+ });
+});
diff --git a/packages/utils/src/date.ts b/packages/utils/src/date.ts
index 42c75c1133..97e9ed026a 100644
--- a/packages/utils/src/date.ts
+++ b/packages/utils/src/date.ts
@@ -19,3 +19,38 @@ export function unixNanoSecondsToSeconds(
): number {
return Number(unixNanoSeconds) / 1000000000;
}
+
+/**
+ * A safe version of setTimeout that splits large timeouts into smaller intervals.
+ * This is necessary because the maximum timeout for setTimeout is 24.8 days.
+ * @param callback - The function to call after the timeout.
+ * @param milliseconds - The number of milliseconds to wait before calling the callback.
+ */
+export function safeTimeout(callback: () => void, milliseconds: number) {
+ const MAX_TIMEOUT = 2 ** 31 - 1; // Maximum safe timeout
+ let timeoutId: NodeJS.Timeout | null = null; // Track the current timeout
+ let cleared = false; // Track if the timeout has been cleared
+
+ const clear = () => {
+ cleared = true; // Mark as cleared
+ if (timeoutId) {
+ clearTimeout(timeoutId); // Clear the current timeout
+ }
+ };
+
+ const runTimeout = (remainingTime: number) => {
+ if (cleared) return; // Do nothing if cleared
+
+ if (remainingTime <= MAX_TIMEOUT) {
+ timeoutId = setTimeout(callback, remainingTime);
+ } else {
+ timeoutId = setTimeout(() => {
+ runTimeout(remainingTime - MAX_TIMEOUT); // Recurse with the remaining time
+ }, MAX_TIMEOUT);
+ }
+ };
+
+ runTimeout(milliseconds);
+
+ return { clear };
+}
diff --git a/packages/web/components/one-click-trading/screens/session-period-screen.tsx b/packages/web/components/one-click-trading/screens/session-period-screen.tsx
index efd59a251c..84bd8f4c28 100644
--- a/packages/web/components/one-click-trading/screens/session-period-screen.tsx
+++ b/packages/web/components/one-click-trading/screens/session-period-screen.tsx
@@ -10,29 +10,26 @@ import {
} from "~/components/screen-manager";
import { useOneClickTradingSession, useTranslation } from "~/hooks";
+export const oneClickTradingTimeMappings = {
+ "1hour": "oneClickTrading.sessionPeriods.1hour",
+ "1day": "oneClickTrading.sessionPeriods.1day",
+ "7days": "oneClickTrading.sessionPeriods.7days",
+ "30days": "oneClickTrading.sessionPeriods.30days",
+};
+
export function getSessionPeriodTranslationKey(
input: OneClickTradingHumanizedSessionPeriod
) {
- const timeMappings = {
- "5min": "oneClickTrading.sessionPeriods.5min",
- "10min": "oneClickTrading.sessionPeriods.10min",
- "30min": "oneClickTrading.sessionPeriods.30min",
- "1hour": "oneClickTrading.sessionPeriods.1hour",
- "3hours": "oneClickTrading.sessionPeriods.3hours",
- "12hours": "oneClickTrading.sessionPeriods.12hours",
- };
- const mapped = timeMappings[input];
+ const mapped = oneClickTradingTimeMappings[input];
if (!mapped) throw new Error(`No mapping for ${input}`);
return mapped;
}
const SessionPeriods: OneClickTradingHumanizedSessionPeriod[] = [
- "5min",
- "10min",
- "30min",
"1hour",
- "3hours",
- "12hours",
+ "1day",
+ "7days",
+ "30days",
];
interface SessionPeriodScreenProps extends OneClickTradingBaseScreenProps {}
diff --git a/packages/web/hooks/mutations/one-click-trading/use-create-one-click-trading-session.tsx b/packages/web/hooks/mutations/one-click-trading/use-create-one-click-trading-session.tsx
index acf1a68b49..2438415920 100644
--- a/packages/web/hooks/mutations/one-click-trading/use-create-one-click-trading-session.tsx
+++ b/packages/web/hooks/mutations/one-click-trading/use-create-one-click-trading-session.tsx
@@ -295,36 +295,27 @@ export async function makeCreate1CTSessionMessage({
let sessionPeriod: OneClickTradingTimeLimit;
switch (transaction1CTParams.sessionPeriod.end) {
- case "5min":
- sessionPeriod = {
- end: unixSecondsToNanoSeconds(dayjs().add(5, "minute").unix()),
- };
- break;
- case "10min":
- sessionPeriod = {
- end: unixSecondsToNanoSeconds(dayjs().add(10, "minute").unix()),
- };
- break;
- case "30min":
+ case "1hour":
sessionPeriod = {
- end: unixSecondsToNanoSeconds(dayjs().add(30, "minute").unix()),
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
};
break;
- case "1hour":
+ case "1day":
sessionPeriod = {
- end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "day").unix()),
};
break;
- case "3hours":
+ case "7days":
sessionPeriod = {
- end: unixSecondsToNanoSeconds(dayjs().add(3, "hours").unix()),
+ end: unixSecondsToNanoSeconds(dayjs().add(7, "day").unix()),
};
break;
- case "12hours":
+ case "30days":
sessionPeriod = {
- end: unixSecondsToNanoSeconds(dayjs().add(12, "hours").unix()),
+ end: unixSecondsToNanoSeconds(dayjs().add(30, "day").unix()),
};
break;
+
default:
throw new Error(
`Unsupported time limit: ${transaction1CTParams.sessionPeriod.end}`
diff --git a/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts b/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts
index 164f9693ae..194f2035df 100644
--- a/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts
+++ b/packages/web/hooks/one-click-trading/__tests__/use-one-click-trading-params.spec.ts
@@ -4,7 +4,7 @@ import {
OneClickTradingHumanizedSessionPeriod,
OneClickTradingTransactionParams,
} from "@osmosis-labs/types";
-import { Dec, PricePretty } from "@osmosis-labs/unit";
+import { Dec, DecUtils, PricePretty } from "@osmosis-labs/unit";
import {
OneClickTradingMaxGasLimit,
unixSecondsToNanoSeconds,
@@ -147,7 +147,7 @@ describe("useOneClickTradingParams", () => {
act(() => {
result.current.setTransaction1CTParams({
...result.current.transaction1CTParams!,
- sessionPeriod: { end: "12hours" },
+ sessionPeriod: { end: "30days" },
});
});
@@ -195,7 +195,7 @@ describe("useOneClickTradingParams", () => {
result.current.setTransaction1CTParams({
...result.current.transaction1CTParams!,
networkFeeLimit: "200000",
- sessionPeriod: { end: "12hours" },
+ sessionPeriod: { end: "30days" },
});
});
@@ -219,7 +219,7 @@ describe("useOneClickTradingParams", () => {
...defaultOneClickTradingInfo,
networkFeeLimit: "200000",
humanizedSessionPeriod:
- "12hours" as OneClickTradingHumanizedSessionPeriod,
+ "1hour" as OneClickTradingHumanizedSessionPeriod,
};
const { result } = renderHook(() =>
@@ -233,7 +233,7 @@ describe("useOneClickTradingParams", () => {
result.current.setTransaction1CTParams({
...result.current.transaction1CTParams!,
networkFeeLimit: "300000",
- sessionPeriod: { end: "3hours" },
+ sessionPeriod: { end: "7days" },
});
});
@@ -259,3 +259,162 @@ describe("useOneClickTradingParams", () => {
});
});
});
+
+describe("getParametersFromOneClickTradingInfo", () => {
+ it("should set isOneClickEnabled based on defaultIsOneClickEnabled", () => {
+ const params = getParametersFromOneClickTradingInfo({
+ oneClickTradingInfo: {
+ networkFeeLimit: "50000",
+ humanizedSessionPeriod: "1hour",
+ spendLimit: { amount: "1000", decimals: 2 },
+ allowedMessages: [],
+ authenticatorId: "test-id",
+ publicKey: "test-key",
+ sessionKey: "test-session",
+ userOsmoAddress: "test-address",
+ hasSeenExpiryToast: false,
+ sessionPeriod: {
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
+ },
+ sessionStartedAtUnix: Date.now(),
+ },
+ defaultIsOneClickEnabled: true,
+ });
+
+ expect(params.isOneClickEnabled).toBe(true);
+ });
+
+ it("should use OneClickTradingMaxGasLimit when networkFeeLimit is not a string", () => {
+ const params = getParametersFromOneClickTradingInfo({
+ oneClickTradingInfo: {
+ // @ts-expect-error - this is to test the networkFeeLimit not being a string
+ networkFeeLimit: 50000,
+ humanizedSessionPeriod: "1hour",
+ spendLimit: { amount: "1000", decimals: 2 },
+ allowedMessages: [],
+ authenticatorId: "test-id",
+ publicKey: "test-key",
+ sessionKey: "test-session",
+ userOsmoAddress: "test-address",
+ hasSeenExpiryToast: false,
+ sessionPeriod: {
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
+ },
+ sessionStartedAtUnix: Date.now(),
+ },
+ defaultIsOneClickEnabled: false,
+ });
+
+ expect(params.networkFeeLimit).toBe(OneClickTradingMaxGasLimit);
+ });
+
+ it("should use the provided networkFeeLimit when it is a string", () => {
+ const customFeeLimit = "75000";
+ const params = getParametersFromOneClickTradingInfo({
+ oneClickTradingInfo: {
+ networkFeeLimit: customFeeLimit,
+ humanizedSessionPeriod: "1hour",
+ spendLimit: { amount: "1000", decimals: 2 },
+ allowedMessages: [],
+ authenticatorId: "test-id",
+ publicKey: "test-key",
+ sessionKey: "test-session",
+ userOsmoAddress: "test-address",
+ hasSeenExpiryToast: false,
+ sessionPeriod: {
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
+ },
+ sessionStartedAtUnix: Date.now(),
+ },
+ defaultIsOneClickEnabled: false,
+ });
+
+ expect(params.networkFeeLimit).toBe(customFeeLimit);
+ });
+
+ it("should map old humanizedSessionPeriod values to '7days'", () => {
+ const oldPeriods = ["5min", "10min", "30min", "3hours", "12hours"] as const;
+
+ oldPeriods.forEach((period) => {
+ const params = getParametersFromOneClickTradingInfo({
+ oneClickTradingInfo: {
+ networkFeeLimit: "50000",
+ // @ts-expect-error - this is to test the old period mapping
+ humanizedSessionPeriod: period,
+ spendLimit: { amount: "1000", decimals: 2 },
+ allowedMessages: [],
+ authenticatorId: "test-id",
+ publicKey: "test-key",
+ sessionKey: "test-session",
+ userOsmoAddress: "test-address",
+ hasSeenExpiryToast: false,
+ sessionPeriod: {
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
+ },
+ sessionStartedAtUnix: Date.now(),
+ },
+ defaultIsOneClickEnabled: true,
+ });
+
+ expect(params.sessionPeriod.end).toBe("7days");
+ });
+ });
+
+ it("should retain humanizedSessionPeriod values that are not old", () => {
+ const newPeriods = ["1day", "7days", "30days"] as const;
+
+ newPeriods.forEach((period) => {
+ const params = getParametersFromOneClickTradingInfo({
+ oneClickTradingInfo: {
+ networkFeeLimit: "50000",
+ humanizedSessionPeriod: period,
+ spendLimit: { amount: "1000", decimals: 2 },
+ allowedMessages: [],
+ authenticatorId: "test-id",
+ publicKey: "test-key",
+ sessionKey: "test-session",
+ userOsmoAddress: "test-address",
+ hasSeenExpiryToast: false,
+ sessionPeriod: {
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
+ },
+ sessionStartedAtUnix: Date.now(),
+ },
+ defaultIsOneClickEnabled: true,
+ });
+
+ expect(params.sessionPeriod.end).toBe(period);
+ });
+ });
+
+ it("should correctly calculate spendLimit", () => {
+ const spendLimit = { amount: "1000", decimals: 2 };
+ const expectedSpendLimitValue = new Dec("1000").quo(
+ DecUtils.getTenExponentN(2)
+ );
+
+ const params = getParametersFromOneClickTradingInfo({
+ oneClickTradingInfo: {
+ networkFeeLimit: "50000",
+ humanizedSessionPeriod: "1hour",
+ spendLimit: spendLimit,
+ allowedMessages: [],
+ authenticatorId: "test-id",
+ publicKey: "test-key",
+ sessionKey: "test-session",
+ userOsmoAddress: "test-address",
+ hasSeenExpiryToast: false,
+ sessionPeriod: {
+ end: unixSecondsToNanoSeconds(dayjs().add(1, "hour").unix()),
+ },
+ sessionStartedAtUnix: Date.now(),
+ },
+ defaultIsOneClickEnabled: true,
+ });
+
+ expect(params.spendLimit.toDec().toString()).toBe(
+ expectedSpendLimitValue.toString()
+ );
+ expect(params.spendLimit.fiatCurrency).toBe(DEFAULT_VS_CURRENCY);
+ });
+});
diff --git a/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts b/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts
index 6c1dc15968..2bb26d9197 100644
--- a/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts
+++ b/packages/web/hooks/one-click-trading/use-one-click-trading-params.ts
@@ -21,6 +21,14 @@ export function getParametersFromOneClickTradingInfo({
oneClickTradingInfo: OneClickTradingInfo;
defaultIsOneClickEnabled: boolean;
}): OneClickTradingTransactionParams {
+ const OldHumanizedSessionPeriods = [
+ "5min",
+ "10min",
+ "30min",
+ "3hours",
+ "12hours",
+ ] as const;
+
return {
isOneClickEnabled: defaultIsOneClickEnabled,
networkFeeLimit:
@@ -28,7 +36,11 @@ export function getParametersFromOneClickTradingInfo({
? OneClickTradingMaxGasLimit
: oneClickTradingInfo.networkFeeLimit,
sessionPeriod: {
- end: oneClickTradingInfo.humanizedSessionPeriod,
+ end: OldHumanizedSessionPeriods.includes(
+ oneClickTradingInfo.humanizedSessionPeriod as (typeof OldHumanizedSessionPeriods)[number]
+ ) // If the session period is one of the old ones, map it to "1hour"
+ ? "7days"
+ : oneClickTradingInfo.humanizedSessionPeriod,
},
spendLimit: new PricePretty(
DEFAULT_VS_CURRENCY,
diff --git a/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts b/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts
index ee170f4f7e..bdbd865ee9 100644
--- a/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts
+++ b/packages/web/hooks/one-click-trading/use-one-click-trading-session.ts
@@ -1,5 +1,5 @@
import type { OneClickTradingInfo } from "@osmosis-labs/stores";
-import { unixNanoSecondsToSeconds } from "@osmosis-labs/utils";
+import { safeTimeout, unixNanoSecondsToSeconds } from "@osmosis-labs/utils";
import dayjs from "dayjs";
import { useCallback, useEffect, useState } from "react";
import { useAsync } from "react-use";
@@ -68,16 +68,16 @@ export const useOneClickTradingSession = ({
const sessionEndDate = dayjs.unix(
unixNanoSecondsToSeconds(value.info.sessionPeriod.end)
);
- const timeRemaining = sessionEndDate.unix() - dayjs().unix();
+ const timeRemainingSeconds = sessionEndDate.unix() - dayjs().unix();
- const timeoutId = setTimeout(() => {
+ const { clear } = safeTimeout(() => {
if (!value?.info) return;
setIsExpired(true);
onExpire?.({ oneClickTradingInfo: value.info });
- }, timeRemaining * 1000);
+ }, timeRemainingSeconds * 1000);
- return () => clearTimeout(timeoutId);
+ return () => clear();
}, [isExpired, t, value?.info, onExpire]);
const getTimeRemaining = useCallback(() => {
diff --git a/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts b/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts
index 643bfaed91..9a525575ed 100644
--- a/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts
+++ b/packages/web/hooks/one-click-trading/use-one-click-trading-swap-review.ts
@@ -3,7 +3,7 @@ import { makeRemoveAuthenticatorMsg } from "@osmosis-labs/tx";
import { OneClickTradingTransactionParams } from "@osmosis-labs/types";
import { Dec, PricePretty } from "@osmosis-labs/unit";
import { useCallback, useEffect, useMemo } from "react";
-import { useAsync } from "react-use";
+import { useAsync, useLocalStorage } from "react-use";
import { create } from "zustand";
import { useShallow } from "zustand/react/shallow";
@@ -21,7 +21,6 @@ const use1CTSwapReviewStore = create<{
transaction1CTParams?: OneClickTradingTransactionParams;
spendLimitTokenDecimals?: number;
changes?: OneClickTradingParamsChanges;
- initialTransactionParams?: OneClickTradingTransactionParams;
setTransaction1CTParams: (
transaction1CTParams: OneClickTradingTransactionParams | undefined
) => void;
@@ -29,21 +28,15 @@ const use1CTSwapReviewStore = create<{
spendLimitTokenDecimals: number | undefined
) => void;
setChanges: (changes: OneClickTradingParamsChanges | undefined) => void;
- setInitialTransactionParams: (
- initialTransactionParams: OneClickTradingTransactionParams | undefined
- ) => void;
}>((set) => ({
spendLimitTokenDecimals: undefined,
transaction1CTParams: undefined,
changes: undefined,
- initialTransactionParams: undefined,
setTransaction1CTParams: (transaction1CTParams) =>
set({ transaction1CTParams }),
setSpendLimitTokenDecimals: (spendLimitTokenDecimals) =>
set({ spendLimitTokenDecimals }),
setChanges: (changes) => set({ changes }),
- setInitialTransactionParams: (initialTransactionParams) =>
- set({ initialTransactionParams }),
}));
export function useOneClickTradingSwapReview({
@@ -51,6 +44,9 @@ export function useOneClickTradingSwapReview({
}: {
isModalOpen: boolean;
}) {
+ const [previousIsOneClickEnabled, setPreviousIsOneClickEnabled] =
+ useLocalStorage("previous-one-click-enabled", true);
+
const {
isOneClickTradingEnabled: isEnabled,
isOneClickTradingExpired: isExpired,
@@ -59,7 +55,6 @@ export function useOneClickTradingSwapReview({
} = useOneClickTradingSession();
const {
- initialTransaction1CTParams: initialTransactionParams,
transaction1CTParams: transactionParams,
setTransaction1CTParams: setTransactionParams,
spendLimitTokenDecimals,
@@ -68,7 +63,7 @@ export function useOneClickTradingSwapReview({
setChanges,
} = useOneClickTradingParams({
oneClickTradingInfo,
- defaultIsOneClickEnabled: isEnabled ?? false,
+ defaultIsOneClickEnabled: previousIsOneClickEnabled,
});
const { wouldExceedSpendLimit, remainingSpendLimit } =
@@ -96,14 +91,6 @@ export function useOneClickTradingSwapReview({
}
}, [isModalOpen, spendLimitTokenDecimals]);
- useEffect(() => {
- if (isModalOpen) {
- use1CTSwapReviewStore
- .getState()
- .setInitialTransactionParams(initialTransactionParams);
- }
- }, [isModalOpen, initialTransactionParams]);
-
useEffect(() => {
if (isModalOpen) {
use1CTSwapReviewStore.getState().setChanges(changes);
@@ -117,7 +104,6 @@ export function useOneClickTradingSwapReview({
state.setTransaction1CTParams(undefined);
state.setSpendLimitTokenDecimals(undefined);
state.setChanges(undefined);
- state.setInitialTransactionParams(undefined);
}
}, [isModalOpen, resetParams]);
@@ -132,6 +118,7 @@ export function useOneClickTradingSwapReview({
remainingSpendLimit,
setTransactionParams,
resetParams,
+ setPreviousIsOneClickEnabled,
};
}
@@ -141,19 +128,14 @@ export function use1CTSwapReviewMessages() {
const { accountStore } = useStore();
const account = accountStore.getWallet(accountStore.osmosisChainId);
- const {
- transaction1CTParams,
- spendLimitTokenDecimals,
- changes,
- initialTransactionParams,
- } = use1CTSwapReviewStore(
- useShallow((state) => ({
- transaction1CTParams: state.transaction1CTParams,
- spendLimitTokenDecimals: state.spendLimitTokenDecimals,
- changes: state.changes,
- initialTransactionParams: state.initialTransactionParams,
- }))
- );
+ const { transaction1CTParams, spendLimitTokenDecimals, changes } =
+ use1CTSwapReviewStore(
+ useShallow((state) => ({
+ transaction1CTParams: state.transaction1CTParams,
+ spendLimitTokenDecimals: state.spendLimitTokenDecimals,
+ changes: state.changes,
+ }))
+ );
const { oneClickTradingInfo, isOneClickTradingEnabled, isLoadingInfo } =
useOneClickTradingSession();
@@ -182,25 +164,10 @@ export function use1CTSwapReviewMessages() {
);
const shouldSend1CTTx = useMemo(() => {
- // Turn on or off: The session status have changed either turned on or off explicitly
- if (
- transaction1CTParams?.isOneClickEnabled !==
- initialTransactionParams?.isOneClickEnabled
- ) {
- return true;
- }
-
- // Modify: The session was already on, wasn't turned off and the params have changed
- if (
- transaction1CTParams?.isOneClickEnabled &&
- initialTransactionParams?.isOneClickEnabled &&
- (changes ?? [])?.length > 0
- ) {
- return true;
- }
-
+ if (isOneClickTradingEnabled && (changes ?? []).length === 0) return false;
+ if (transaction1CTParams?.isOneClickEnabled) return true;
return false;
- }, [transaction1CTParams, initialTransactionParams, changes]);
+ }, [transaction1CTParams, changes, isOneClickTradingEnabled]);
const { value: oneClickMessages, loading: isLoadingOneClickMessages } =
useAsync(async () => {
diff --git a/packages/web/localizations/de.json b/packages/web/localizations/de.json
index 1990711c97..7de8bc7782 100644
--- a/packages/web/localizations/de.json
+++ b/packages/web/localizations/de.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 Minuten",
- "10min": "10 Minuten",
- "30min": "30 Minuten",
"1hour": "1 Stunde",
- "3hours": "3 Stunden",
- "12hours": "12 Stunden"
+ "1day": "1 Tag",
+ "7days": "7 Tage",
+ "30days": "30 Tage"
},
"settings": {
"header": "1-Klick-Handel",
@@ -1104,7 +1102,7 @@
"hour": "Std",
"hours": "Std",
"day": "Tag",
- "days": "Tag"
+ "days": "Tage"
},
"transactions": {
"noRecent": "Keine aktuellen Transfers",
diff --git a/packages/web/localizations/en.json b/packages/web/localizations/en.json
index 4b261a8723..e82f34fa9e 100644
--- a/packages/web/localizations/en.json
+++ b/packages/web/localizations/en.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 minutes",
- "10min": "10 minutes",
- "30min": "30 minutes",
"1hour": "1 hour",
- "3hours": "3 hours",
- "12hours": "12 hours"
+ "1day": "1 day",
+ "7days": "7 days",
+ "30days": "30 days"
},
"settings": {
"header": "1-Click Trading",
@@ -1104,7 +1102,7 @@
"hour": "hr",
"hours": "hr",
"day": "day",
- "days": "day"
+ "days": "days"
},
"transactions": {
"noRecent": "No recent transactions",
diff --git a/packages/web/localizations/es.json b/packages/web/localizations/es.json
index f51578fdc3..463237c081 100644
--- a/packages/web/localizations/es.json
+++ b/packages/web/localizations/es.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 minutos",
- "10min": "10 minutos",
- "30min": "30 minutos",
"1hour": "1 hora",
- "3hours": "3 horas",
- "12hours": "12 horas"
+ "1day": "1 día",
+ "7days": "7 días",
+ "30days": "30 días"
},
"settings": {
"header": "Comercio con 1 clic",
@@ -1104,7 +1102,7 @@
"hour": "hora",
"hours": "hora",
"day": "día",
- "days": "día"
+ "days": "días"
},
"transactions": {
"noRecent": "Sin transferencias recientes",
diff --git a/packages/web/localizations/fa.json b/packages/web/localizations/fa.json
index 5f03d94a06..c8863ce971 100644
--- a/packages/web/localizations/fa.json
+++ b/packages/web/localizations/fa.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 دقیقه",
- "10min": "10 دقیقه",
- "30min": "30 دقیقه",
"1hour": "1 ساعت",
- "3hours": "3 ساعت",
- "12hours": "12 ساعت"
+ "1day": "1 روز",
+ "7days": "7 روز",
+ "30days": "30 روز"
},
"settings": {
"header": "1- روی تجارت کلیک کنید",
diff --git a/packages/web/localizations/fr.json b/packages/web/localizations/fr.json
index 2acc02b7ac..b83af190f2 100644
--- a/packages/web/localizations/fr.json
+++ b/packages/web/localizations/fr.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 minutes",
- "10min": "10 minutes",
- "30min": "30 minutes",
"1hour": "1 heure",
- "3hours": "3 heures",
- "12hours": "12 heures"
+ "1day": "1 jour",
+ "7days": "7 jours",
+ "30days": "30 jours"
},
"settings": {
"header": "Trading en 1 clic",
@@ -1104,7 +1102,7 @@
"hour": "heure",
"hours": "heure",
"day": "jour",
- "days": "jour"
+ "days": "jours"
},
"transactions": {
"noRecent": "Aucun transfert récent",
diff --git a/packages/web/localizations/gu.json b/packages/web/localizations/gu.json
index d5f79970e8..2dcb5d1346 100644
--- a/packages/web/localizations/gu.json
+++ b/packages/web/localizations/gu.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 મિનિટ",
- "10min": "10 મિનિટ",
- "30min": "30 મિનિટ",
"1hour": "1 કલાક",
- "3hours": "3 કલાક",
- "12hours": "12 કલાક"
+ "1day": "1 દિવસ",
+ "7days": "7 દિવસ",
+ "30days": "30 દિવસ"
},
"settings": {
"header": "1-ક્લિક કરો ટ્રેડિંગ",
@@ -1104,7 +1102,7 @@
"hour": "કલાક",
"hours": "કલાક",
"day": "દિવસ",
- "days": "દિવસ"
+ "days": "દિવસો"
},
"transactions": {
"noRecent": "કોઈ તાજેતરના ટ્રાન્સફર નથી",
diff --git a/packages/web/localizations/hi.json b/packages/web/localizations/hi.json
index 238015367a..79d85cf6bd 100644
--- a/packages/web/localizations/hi.json
+++ b/packages/web/localizations/hi.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 मिनट",
- "10min": "10 मिनटों",
- "30min": "30 मिनट",
"1hour": "1 घंटा",
- "3hours": "3 घंटे",
- "12hours": "12 घंटे"
+ "1day": "1 दिन",
+ "7days": "7 दिन",
+ "30days": "30 दिन"
},
"settings": {
"header": "1-ट्रेडिंग पर क्लिक करें",
diff --git a/packages/web/localizations/ja.json b/packages/web/localizations/ja.json
index 46af580a25..3962007d2f 100644
--- a/packages/web/localizations/ja.json
+++ b/packages/web/localizations/ja.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5分",
- "10min": "10分",
- "30min": "30分",
"1hour": "1時間",
- "3hours": "3時間",
- "12hours": "12時間"
+ "1day": "1日",
+ "7days": "7日間",
+ "30days": "30日間"
},
"settings": {
"header": "1クリック取引",
diff --git a/packages/web/localizations/ko.json b/packages/web/localizations/ko.json
index dada7b9697..f2a53be22d 100644
--- a/packages/web/localizations/ko.json
+++ b/packages/web/localizations/ko.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5분",
- "10min": "10분",
- "30min": "30분",
"1hour": "1시간",
- "3hours": "3시간",
- "12hours": "12시간"
+ "1day": "1일",
+ "7days": "7일",
+ "30days": "30일"
},
"settings": {
"header": "1-클릭 거래",
@@ -1104,7 +1102,7 @@
"hour": "시간",
"hours": "시간",
"day": "낮",
- "days": "낮"
+ "days": "날"
},
"transactions": {
"noRecent": "최근 이적 없음",
diff --git a/packages/web/localizations/pl.json b/packages/web/localizations/pl.json
index 5f9cc1dae1..ecdd1bfd5a 100644
--- a/packages/web/localizations/pl.json
+++ b/packages/web/localizations/pl.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 minut",
- "10min": "10 minut",
- "30min": "30 minut",
"1hour": "1 godzina",
- "3hours": "3 godziny",
- "12hours": "12 godzin"
+ "1day": "1 dzień",
+ "7days": "7 dni",
+ "30days": "30 dni"
},
"settings": {
"header": "Handel jednym kliknięciem",
@@ -1104,7 +1102,7 @@
"hour": "godz.",
"hours": "godz.",
"day": "dzień",
- "days": "dzień"
+ "days": "dni"
},
"transactions": {
"noRecent": "Brak ostatnich transferów",
diff --git a/packages/web/localizations/pt-br.json b/packages/web/localizations/pt-br.json
index 6dfeb21360..d3c8f34b94 100644
--- a/packages/web/localizations/pt-br.json
+++ b/packages/web/localizations/pt-br.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 minutos",
- "10min": "10 minutos",
- "30min": "30 minutos",
"1hour": "1 hora",
- "3hours": "3 horas",
- "12hours": "12 horas"
+ "1day": "1 dia",
+ "7days": "7 dias",
+ "30days": "30 dias"
},
"settings": {
"header": "Negociação em 1 clique",
@@ -1104,7 +1102,7 @@
"hour": "hora",
"hours": "hora",
"day": "dia",
- "days": "dia"
+ "days": "dias"
},
"transactions": {
"noRecent": "Nenhuma transferência recente",
diff --git a/packages/web/localizations/ro.json b/packages/web/localizations/ro.json
index 34601e55f3..f30052567d 100644
--- a/packages/web/localizations/ro.json
+++ b/packages/web/localizations/ro.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 minute",
- "10min": "10 minute",
- "30min": "30 de minute",
"1hour": "1 oră",
- "3hours": "3 ore",
- "12hours": "12 ore"
+ "1day": "1 zi",
+ "7days": "7 zile",
+ "30days": "30 de zile"
},
"settings": {
"header": "1-Click Trading",
@@ -1104,7 +1102,7 @@
"hour": "hr",
"hours": "hr",
"day": "zi",
- "days": "zi"
+ "days": "zile"
},
"transactions": {
"noRecent": "Fără transferuri recente",
diff --git a/packages/web/localizations/ru.json b/packages/web/localizations/ru.json
index 6674b7156a..46cfddb2e3 100644
--- a/packages/web/localizations/ru.json
+++ b/packages/web/localizations/ru.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 минут",
- "10min": "10 минут",
- "30min": "30 минут",
"1hour": "1 час",
- "3hours": "3 часа",
- "12hours": "12 часов"
+ "1day": "1 день",
+ "7days": "7 дней",
+ "30days": "30 дней"
},
"settings": {
"header": "Торговля в 1 клик",
@@ -1104,7 +1102,7 @@
"hour": "час",
"hours": "час",
"day": "день",
- "days": "день"
+ "days": "дней"
},
"transactions": {
"noRecent": "Нет недавних переводов",
diff --git a/packages/web/localizations/tr.json b/packages/web/localizations/tr.json
index 39179a17db..3d68a242a5 100644
--- a/packages/web/localizations/tr.json
+++ b/packages/web/localizations/tr.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 dakika",
- "10min": "10 dakika",
- "30min": "30 dakika",
"1hour": "1 saat",
- "3hours": "3 saat",
- "12hours": "12 saat"
+ "1day": "1 gün",
+ "7days": "7 gün",
+ "30days": "30 gün"
},
"settings": {
"header": "Tek Tıklamayla Ticaret",
@@ -1104,7 +1102,7 @@
"hour": "saat",
"hours": "saat",
"day": "gün",
- "days": "gün"
+ "days": "günler"
},
"transactions": {
"noRecent": "Yakın zamanda transfer yok",
diff --git a/packages/web/localizations/zh-cn.json b/packages/web/localizations/zh-cn.json
index b7a4a7483c..d900572c35 100644
--- a/packages/web/localizations/zh-cn.json
+++ b/packages/web/localizations/zh-cn.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5 分钟",
- "10min": "10 分钟",
- "30min": "30 分钟",
"1hour": "1 小时",
- "3hours": "3 小时",
- "12hours": "12 小时"
+ "1day": "1天",
+ "7days": "7 天",
+ "30days": "30 天"
},
"settings": {
"header": "一键交易",
diff --git a/packages/web/localizations/zh-hk.json b/packages/web/localizations/zh-hk.json
index e32ab0acd4..e646b585df 100644
--- a/packages/web/localizations/zh-hk.json
+++ b/packages/web/localizations/zh-hk.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5分鐘",
- "10min": "10分鐘",
- "30min": "30分鐘",
"1hour": "1小時",
- "3hours": "3小時",
- "12hours": "12小時"
+ "1day": "1天",
+ "7days": "7天",
+ "30days": "30天"
},
"settings": {
"header": "一鍵交易",
diff --git a/packages/web/localizations/zh-tw.json b/packages/web/localizations/zh-tw.json
index 09532f6902..48e02280ef 100644
--- a/packages/web/localizations/zh-tw.json
+++ b/packages/web/localizations/zh-tw.json
@@ -398,12 +398,10 @@
}
},
"sessionPeriods": {
- "5min": "5分鐘",
- "10min": "10分鐘",
- "30min": "30分鐘",
"1hour": "1小時",
- "3hours": "3小時",
- "12hours": "12小時"
+ "1day": "1天",
+ "7days": "7天",
+ "30days": "30天"
},
"settings": {
"header": "一鍵交易",
diff --git a/packages/web/modals/review-order.tsx b/packages/web/modals/review-order.tsx
index e37bdc5f9b..d484e347a6 100644
--- a/packages/web/modals/review-order.tsx
+++ b/packages/web/modals/review-order.tsx
@@ -19,6 +19,7 @@ import { Icon } from "~/components/assets";
import { Button } from "~/components/buttons";
import { OneClickTradingRemainingTime } from "~/components/one-click-trading/one-click-remaining-time";
import { OneClickTradingSettings } from "~/components/one-click-trading/one-click-trading-settings";
+import { oneClickTradingTimeMappings } from "~/components/one-click-trading/screens/session-period-screen";
import { GenericDisclaimer } from "~/components/tooltip/generic-disclaimer";
import { Button as UIButton } from "~/components/ui/button";
import { RecapRow } from "~/components/ui/recap-row";
@@ -129,6 +130,7 @@ export function ReviewOrder({
wouldExceedSpendLimit: wouldExceedSpendLimit1CT,
setTransactionParams: setTransaction1CTParams,
resetParams: reset1CTParams,
+ setPreviousIsOneClickEnabled,
} = useOneClickTradingSwapReview({ isModalOpen: isOpen });
const wouldExceedSpendLimit = useMemo(() => {
@@ -749,6 +751,8 @@ export function ReviewOrder({
setTransaction1CTParams((prev) => {
if (!prev) return;
+ setPreviousIsOneClickEnabled(!prev.isOneClickEnabled);
+
return {
...prev,
isOneClickEnabled: !prev.isOneClickEnabled,
@@ -924,9 +928,12 @@ const OneClickTradingActiveSessionParamsEdit = ({
{remainingSpendLimit}
)}
{" / "}
- {changes.includes("sessionPeriod") ? (
+ {changes.includes("sessionPeriod") &&
+ transactionParams?.sessionPeriod.end ? (
- {transactionParams?.sessionPeriod.end}
+ {t(
+ oneClickTradingTimeMappings[transactionParams.sessionPeriod.end]
+ )}
) : (
diff --git a/packages/web/utils/date.ts b/packages/web/utils/date.ts
index af4f375a5b..936a6bc5d6 100644
--- a/packages/web/utils/date.ts
+++ b/packages/web/utils/date.ts
@@ -73,6 +73,7 @@ export function humanizeTime(
const daysDiff = date.diff(dayjs(), "days");
if (daysDiff < 30) {
+ const hours = date.diff(dayjs(), "hours") % 24;
return [
{
value: daysDiff,
@@ -85,6 +86,17 @@ export function humanizeTime(
? "timeUnitsShort.days"
: "timeUnits.days",
},
+ {
+ value: hours,
+ unitTranslationKey:
+ hours === 1
+ ? useShortTimeUnits
+ ? "timeUnitsShort.hour"
+ : "timeUnits.hour"
+ : useShortTimeUnits
+ ? "timeUnitsShort.hours"
+ : "timeUnits.hours",
+ },
];
}