From 72b6204207836f325bf52b3a7e77c8b3a5b1fdfc Mon Sep 17 00:00:00 2001 From: Alex Panturu Date: Thu, 22 Feb 2024 13:23:25 +0200 Subject: [PATCH] web-wallet: fix localStorage gas limits update on ENV change --- .../components/GasControls/GasControls.svelte | 20 +++-------- .../components/GasSettings/GasSettings.svelte | 10 ++++++ .../src/lib/components/Send/Send.svelte | 20 ++++++----- .../src/lib/components/Stake/Stake.svelte | 28 +++++++++------- .../components/__tests__/GasControls.spec.js | 33 +------------------ .../components/__tests__/GasSettings.spec.js | 7 ++-- .../src/lib/components/__tests__/Send.spec.js | 8 ++--- .../lib/components/__tests__/Stake.spec.js | 8 ++--- .../StakeContract/StakeContract.svelte | 2 ++ .../TransferContract/TransferContract.svelte | 9 +++-- web-wallet/src/lib/contracts/contracts.d.ts | 3 -- web-wallet/src/lib/stores/gasStore.js | 33 +++++++++++++++++++ web-wallet/src/lib/stores/index.js | 1 + web-wallet/src/lib/stores/settingsStore.js | 3 -- web-wallet/src/lib/stores/stores.d.ts | 12 +++++++ .../src/routes/(app)/settings/+page.svelte | 26 +++++++-------- 16 files changed, 118 insertions(+), 105 deletions(-) create mode 100644 web-wallet/src/lib/stores/gasStore.js diff --git a/web-wallet/src/lib/components/GasControls/GasControls.svelte b/web-wallet/src/lib/components/GasControls/GasControls.svelte index af6d7eae8..de315a37e 100644 --- a/web-wallet/src/lib/components/GasControls/GasControls.svelte +++ b/web-wallet/src/lib/components/GasControls/GasControls.svelte @@ -2,7 +2,6 @@ @@ -54,7 +42,7 @@ className="gas-control__input" max={limit} min={priceLower} - on:input={checkGasLimits} + on:input={dispatchGasLimits} required type="number" /> @@ -69,7 +57,7 @@ className="gas-control__input" max={limitUpper} min={limitLower} - on:input={checkGasLimits} + on:input={dispatchGasLimits} required type="number" /> diff --git a/web-wallet/src/lib/components/GasSettings/GasSettings.svelte b/web-wallet/src/lib/components/GasSettings/GasSettings.svelte index 73f40b0c0..5d4ad2fbe 100644 --- a/web-wallet/src/lib/components/GasSettings/GasSettings.svelte +++ b/web-wallet/src/lib/components/GasSettings/GasSettings.svelte @@ -2,6 +2,7 @@ import { slide } from "svelte/transition"; import { Button } from "$lib/dusk/components"; import { GasControls, GasFee } from "$lib/components"; + import { onMount } from "svelte"; /** @type {number} */ export let limit; @@ -21,8 +22,17 @@ /** @type {string} */ export let fee; + /** @type {import("$lib/stores/stores").GasStore} */ + export let gasStore; + /** @type {boolean} */ let isExpanded = false; + + onMount(() => { + if (!gasStore.areValidSettings(price, limit)) { + isExpanded = true; + } + });
diff --git a/web-wallet/src/lib/components/Send/Send.svelte b/web-wallet/src/lib/components/Send/Send.svelte index c76653b80..b88d1ce1f 100644 --- a/web-wallet/src/lib/components/Send/Send.svelte +++ b/web-wallet/src/lib/components/Send/Send.svelte @@ -41,6 +41,9 @@ /** @type {ContractStatus[]} */ export let statuses; + /** @type {import("$lib/stores/stores").GasStore} */ + export let gasStore; + /** @type {number} */ let amount = 1; @@ -56,13 +59,12 @@ /** @type {HTMLInputElement | null} */ let amountInput; - /** @type {boolean} */ - let isValidGas = true; - /** @type {boolean} */ let isNextButtonDisabled = false; + let isValidGas = false; let { gasLimit, gasPrice } = gasSettings; + const { limitLower, limitUpper, priceLower } = $gasStore; const minAmount = 0.000000001; @@ -71,6 +73,7 @@ onMount(() => { amountInput = document.querySelector(".operation__input-field"); + isValidGas = gasStore.areValidSettings(gasPrice, gasLimit); }); $: luxFee = gasLimit * gasPrice; @@ -132,15 +135,16 @@ { - isValidGas = event.detail.isValidGas; + isValidGas = gasStore.areValidSettings(event.detail.price, event.detail.limit); - if (event.detail.isValidGas) { + if (isValidGas) { gasPrice = event.detail.price; gasLimit = event.detail.limit; } diff --git a/web-wallet/src/lib/components/Stake/Stake.svelte b/web-wallet/src/lib/components/Stake/Stake.svelte index 387cd10cd..5d8729bb9 100644 --- a/web-wallet/src/lib/components/Stake/Stake.svelte +++ b/web-wallet/src/lib/components/Stake/Stake.svelte @@ -58,6 +58,9 @@ /** @type {boolean} */ export let hideStakingNotice; + /** @type {import("$lib/stores/stores").GasStore} */ + export let gasStore; + const defaultMinStake = 1000; /** @type {number} */ @@ -70,13 +73,12 @@ /** @type {HTMLInputElement|null} */ let stakeInput; - /** @type {boolean} */ - let isValidGas = true; - /** @type {boolean} */ let hideStakingNoticeNextTime = false; + let isValidGas = false; let { gasLimit, gasPrice } = gasSettings; + const { limitLower, limitUpper, priceLower } = $gasStore; /** @type {Record} */ const confirmLabels = { @@ -100,9 +102,9 @@ * @param {{detail:{price:number, limit:number, isValidGas:boolean}}} event */ const setGasValues = (event) => { - isValidGas = event.detail.isValidGas; + isValidGas = gasStore.areValidSettings(event.detail.price, event.detail.limit); - if (event.detail.isValidGas) { + if (isValidGas) { gasPrice = event.detail.price; gasLimit = event.detail.limit; } @@ -112,6 +114,8 @@ if (flow === "stake") { stakeAmount = Math.min(minStake, stakeAmount); } + + isValidGas = gasStore.areValidSettings(gasPrice, gasLimit); }); $: luxFee = gasLimit * gasPrice; @@ -222,11 +226,12 @@ @@ -266,11 +271,12 @@ {:else} {/if} diff --git a/web-wallet/src/lib/components/__tests__/GasControls.spec.js b/web-wallet/src/lib/components/__tests__/GasControls.spec.js index 803459922..3668358c7 100644 --- a/web-wallet/src/lib/components/__tests__/GasControls.spec.js +++ b/web-wallet/src/lib/components/__tests__/GasControls.spec.js @@ -57,7 +57,7 @@ describe("GasControls", () => { expect(container).toMatchSnapshot(); }); - it("should dispatch a \"gasSettings\" event when the price or the limit are changed with valid gas settings", async () => { + it("should dispatch a \"gasSettings\" event when the price or the limit are changed", async () => { const { component, getByLabelText } = render(GasControls, baseOptions); const priceInput = asInput(getByLabelText(/price/i)); const limitInput = asInput(getByLabelText(/limit/i)); @@ -68,7 +68,6 @@ describe("GasControls", () => { expect(eventHandler).toHaveBeenCalledTimes(1); expect(eventHandler.mock.lastCall[0].detail).toStrictEqual({ - isValidGas: true, limit: baseProps.limit, price: 15 }); @@ -78,40 +77,10 @@ describe("GasControls", () => { expect(eventHandler).toHaveBeenCalledTimes(2); expect(eventHandler.mock.lastCall[0].detail).toStrictEqual({ - isValidGas: true, limit: 25, price: 15 }); expect(limitInput.valueAsNumber).toBe(25); expect(priceInput.max).toBe("25"); }); - - it("should dispatch a \"gasSettings\" event when the price or the limit are changed with invalid gas settings", async () => { - const { component, getByLabelText } = render(GasControls, baseOptions); - const priceInput = asInput(getByLabelText(/price/i)); - const limitInput = asInput(getByLabelText(/limit/i)); - - component.$on("gasSettings", eventHandler); - - await fireInput(priceInput, 25); - - expect(eventHandler).toHaveBeenCalledTimes(1); - expect(eventHandler.mock.lastCall[0].detail).toStrictEqual({ - isValidGas: false, - limit: baseProps.limit, - price: 25 - }); - expect(priceInput.valueAsNumber).toBe(25); - - await fireInput(limitInput, 105); - - expect(eventHandler).toHaveBeenCalledTimes(2); - expect(eventHandler.mock.lastCall[0].detail).toStrictEqual({ - isValidGas: false, - limit: 105, - price: 25 - }); - expect(limitInput.valueAsNumber).toBe(105); - expect(priceInput.max).toBe("105"); - }); }); diff --git a/web-wallet/src/lib/components/__tests__/GasSettings.spec.js b/web-wallet/src/lib/components/__tests__/GasSettings.spec.js index 040d647ae..363458a6f 100644 --- a/web-wallet/src/lib/components/__tests__/GasSettings.spec.js +++ b/web-wallet/src/lib/components/__tests__/GasSettings.spec.js @@ -9,7 +9,7 @@ import { cleanup, fireEvent, render } from "@testing-library/svelte"; import { GasSettings } from ".."; import { get } from "svelte/store"; -import { settingsStore } from "$lib/stores"; +import { gasStore, settingsStore } from "$lib/stores"; import { createCurrencyFormatter } from "$lib/dusk/currency"; describe("GasSettings", () => { @@ -23,7 +23,8 @@ describe("GasSettings", () => { limitLower: 10000000, limitUpper: 1000000000, price: 1, - priceLower: 1 + priceLower: 1, + gasStore: gasStore }; const baseOptions = { @@ -66,7 +67,6 @@ describe("GasSettings", () => { expect(eventHandler).toHaveBeenCalledTimes(1); expect(eventHandler.mock.lastCall[0].detail).toStrictEqual({ - isValidGas: true, limit: baseProps.limitLower, price: baseProps.price }); @@ -75,7 +75,6 @@ describe("GasSettings", () => { expect(eventHandler).toHaveBeenCalledTimes(2); expect(eventHandler.mock.lastCall[0].detail).toStrictEqual({ - isValidGas: true, limit: baseProps.limitLower, price: baseProps.price * 2 }); diff --git a/web-wallet/src/lib/components/__tests__/Send.spec.js b/web-wallet/src/lib/components/__tests__/Send.spec.js index 4fbaa3788..afea74696 100644 --- a/web-wallet/src/lib/components/__tests__/Send.spec.js +++ b/web-wallet/src/lib/components/__tests__/Send.spec.js @@ -7,7 +7,7 @@ import { vi } from "vitest"; import { cleanup, fireEvent, render } from "@testing-library/svelte"; - +import { gasStore } from "$lib/stores"; import { deductLuxFeeFrom } from "$lib/contracts"; import { createCurrencyFormatter } from "$lib/dusk/currency"; import { getAsHTMLElement } from "$lib/dusk/test-helpers"; @@ -23,11 +23,9 @@ describe("Send", () => { formatter, gasSettings: { gasLimit: 20000000, - gasLimitLower: 10000000, - gasLimitUpper: 1000000000, - gasPrice: 1, - gasPriceLower: 1 + gasPrice: 1 }, + gasStore: gasStore, spendable: 1000, statuses: [{ label: "Spendable", diff --git a/web-wallet/src/lib/components/__tests__/Stake.spec.js b/web-wallet/src/lib/components/__tests__/Stake.spec.js index 2bcda32f8..72e5edf52 100644 --- a/web-wallet/src/lib/components/__tests__/Stake.spec.js +++ b/web-wallet/src/lib/components/__tests__/Stake.spec.js @@ -7,7 +7,7 @@ import { vi } from "vitest"; import { cleanup, fireEvent, render } from "@testing-library/svelte"; - +import { gasStore } from "$lib/stores"; import { deductLuxFeeFrom } from "$lib/contracts"; import { createCurrencyFormatter } from "$lib/dusk/currency"; @@ -32,11 +32,9 @@ describe("Stake", () => { formatter, gasSettings: { gasLimit: 20000000, - gasLimitLower: 10000000, - gasLimitUpper: 1000000000, - gasPrice: 1, - gasPriceLower: 1 + gasPrice: 1 }, + gasStore: gasStore, hideStakingNotice: true, rewards: 345, spendable: 10000, diff --git a/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte b/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte index 8c4d0a0a2..cd4caafce 100644 --- a/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte +++ b/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte @@ -16,6 +16,7 @@ import { createCurrencyFormatter } from "$lib/dusk/currency"; import { getLastTransactionHash } from "$lib/transactions"; import { + gasStore, operationsStore, settingsStore, walletStore @@ -131,6 +132,7 @@ flow={currentOperation} formatter={duskFormatter} {gasSettings} + {gasStore} on:operationChange on:suppressStakingNotice rewards={stakeInfo.reward} diff --git a/web-wallet/src/lib/containers/TransferContract/TransferContract.svelte b/web-wallet/src/lib/containers/TransferContract/TransferContract.svelte index 689d79eb0..e499f3e3d 100644 --- a/web-wallet/src/lib/containers/TransferContract/TransferContract.svelte +++ b/web-wallet/src/lib/containers/TransferContract/TransferContract.svelte @@ -15,6 +15,7 @@ import { createCurrencyFormatter } from "$lib/dusk/currency"; import { getLastTransactionHash } from "$lib/transactions"; import { + gasStore, operationsStore, settingsStore, walletStore @@ -34,7 +35,7 @@ walletStore.transfer(to, amount, gasPrice, gasLimit).then(getLastTransactionHash); const collectSettings = collect([ - pick(["gasLimit", "gasLimitLower", "gasLimitUpper", "gasPrice", "gasPriceLower"]), + pick(["gasLimit", "gasPrice"]), getKey("language") ]); const isEnabledSend = allOf([ @@ -43,10 +44,7 @@ ]); $: ({ currentOperation } = $operationsStore); - $: [ - gasSettings, - language - ] = collectSettings($settingsStore); + $: [gasSettings, language] = collectSettings($settingsStore); $: ({ balance, currentAddress, @@ -75,6 +73,7 @@ execute={executeSend} formatter={duskFormatter} {gasSettings} + {gasStore} on:operationChange spendable={balance.maximum} {statuses} diff --git a/web-wallet/src/lib/contracts/contracts.d.ts b/web-wallet/src/lib/contracts/contracts.d.ts index e7034a6f8..17997f397 100644 --- a/web-wallet/src/lib/contracts/contracts.d.ts +++ b/web-wallet/src/lib/contracts/contracts.d.ts @@ -7,10 +7,7 @@ type ContractDescriptor = { type ContractGasSettings = { gasLimit: number; - gasLimitLower: number; - gasLimitUpper: number; gasPrice: number; - gasPriceLower: number; }; type ContractOperation = { diff --git a/web-wallet/src/lib/stores/gasStore.js b/web-wallet/src/lib/stores/gasStore.js new file mode 100644 index 000000000..31e77df17 --- /dev/null +++ b/web-wallet/src/lib/stores/gasStore.js @@ -0,0 +1,33 @@ +import { readable } from "svelte/store"; +import { isType } from "lamb"; + +const gasSettings = { + limitLower: Number(parseInt(import.meta.env.VITE_GAS_LIMIT_LOWER, 10)), + limitUpper: Number(parseInt(import.meta.env.VITE_GAS_LIMIT_UPPER, 10)), + priceLower: Number(parseInt(import.meta.env.VITE_GAS_PRICE_LOWER, 10)) +}; + +const gasStore = readable(gasSettings); +const { subscribe } = gasStore; + +/** + * + * @param {Number} price + * @param {Number} limit + * @returns {Boolean} + */ +const areValidSettings = (price, limit) => { + let isValidPrice = false; + let isValidLimit = false; + let isValidGas = false; + + if ([price, limit].every(isType("Number"))) { + isValidPrice = price >= gasSettings.priceLower && price <= limit; + isValidLimit = limit >= gasSettings.limitLower && limit <= gasSettings.limitUpper; + isValidGas = isValidPrice && isValidLimit; + } + + return isValidGas; +}; + +export default { areValidSettings, subscribe }; diff --git a/web-wallet/src/lib/stores/index.js b/web-wallet/src/lib/stores/index.js index d3526705f..d2d1c8b98 100644 --- a/web-wallet/src/lib/stores/index.js +++ b/web-wallet/src/lib/stores/index.js @@ -1,3 +1,4 @@ +export { default as gasStore } from "./gasStore"; export { default as operationsStore } from "./operationsStore"; export { default as settingsStore } from "./settingsStore"; export { default as walletStore } from "./walletStore"; diff --git a/web-wallet/src/lib/stores/settingsStore.js b/web-wallet/src/lib/stores/settingsStore.js index 0eb680d03..893b2cb3b 100644 --- a/web-wallet/src/lib/stores/settingsStore.js +++ b/web-wallet/src/lib/stores/settingsStore.js @@ -6,10 +6,7 @@ const initialState = { darkMode: false, dashboardTransactionLimit: 5, gasLimit: parseInt(import.meta.env.VITE_GAS_LIMIT_DEFAULT, 10), - gasLimitLower: parseInt(import.meta.env.VITE_GAS_LIMIT_LOWER, 10), - gasLimitUpper: parseInt(import.meta.env.VITE_GAS_LIMIT_UPPER, 10), gasPrice: parseInt(import.meta.env.VITE_GAS_PRICE_DEFAULT, 10), - gasPriceLower: parseInt(import.meta.env.VITE_GAS_PRICE_LOWER, 10), hideStakingNotice: false, language: browser ? navigator.language : "en", network: "testnet", diff --git a/web-wallet/src/lib/stores/stores.d.ts b/web-wallet/src/lib/stores/stores.d.ts index db6964132..c46ae68ce 100644 --- a/web-wallet/src/lib/stores/stores.d.ts +++ b/web-wallet/src/lib/stores/stores.d.ts @@ -62,3 +62,15 @@ type SettingsStore = { network: string; userId: string; }; + +type GasStoreContent = { + limitLower: number, + limitUpper: number, + priceLower: number +} + +type GasStoreService = { + areValidSettings: (gasPrice:number, gasLimit:number) => boolean; +} + +type GasStore = Readable & GasStoreService; diff --git a/web-wallet/src/routes/(app)/settings/+page.svelte b/web-wallet/src/routes/(app)/settings/+page.svelte index 59f790272..f39d1d6c2 100644 --- a/web-wallet/src/routes/(app)/settings/+page.svelte +++ b/web-wallet/src/routes/(app)/settings/+page.svelte @@ -23,7 +23,7 @@ } from "$lib/dusk/components"; import { GasControls } from "$lib/components"; import { currencies } from "$lib/dusk/currency"; - import { settingsStore, walletStore } from "$lib/stores"; + import { gasStore, settingsStore, walletStore } from "$lib/stores"; const resetWallet = () => walletStore.clearLocalData().then(() => { settingsStore.reset(); @@ -45,25 +45,25 @@ currency, darkMode, gasLimit, - gasLimitLower, - gasLimitUpper, gasPrice, - gasPriceLower, network } = $settingsStore; + const { + limitLower, + limitUpper, + priceLower + } = $gasStore; const networks = [ { label: "testnet", value: "testnet" }, { disabled: true, label: "mainnet", value: "mainnet" } ]; let isDarkMode = darkMode; + let isValidGas = false; /** @type {Error | null} */ let resetError = null; - /** @type {Boolean} */ - let isValidGas = false; - $: ({ isSyncing } = $walletStore); @@ -137,7 +137,9 @@
{ - if (event.detail.isValidGas) { + isValidGas = gasStore.areValidSettings(event.detail.price, event.detail.limit); + + if (isValidGas) { settingsStore.update(store => { store.gasLimit = event.detail.limit; store.gasPrice = event.detail.price; @@ -145,14 +147,12 @@ return store; }); } - - isValidGas = event.detail.isValidGas; }} limit={gasLimit} - limitLower={gasLimitLower} - limitUpper={gasLimitUpper} + limitLower={limitLower} + limitUpper={limitUpper} price={gasPrice} - priceLower={gasPriceLower} + priceLower={priceLower} />