Repository: dusk-network/rusk (language: rust)

Issue:
Update to latest w3sper for Stake contract changes
#### Summary

See https://github.com/dusk-network/rusk/pull/3132


Discussion / hints:

Fix patch:
diff --git a/web-wallet/src/__mocks__/ProtocolDriver.js b/web-wallet/src/__mocks__/ProtocolDriver.js
index 14c1e17a0f..d66f7cad7d 100644
--- a/web-wallet/src/__mocks__/ProtocolDriver.js
+++ b/web-wallet/src/__mocks__/ProtocolDriver.js
@@ -20,3 +20,5 @@ export async function getMinimumStake() {
 export function load() {}
 
 export async function unload() {}
+
+export function useAsProtocolDriver() {}
diff --git a/web-wallet/src/lib/mock-data/cache-stake-info.js b/web-wallet/src/lib/mock-data/cache-stake-info.js
index f6e78a4b6a..af97733997 100644
--- a/web-wallet/src/lib/mock-data/cache-stake-info.js
+++ b/web-wallet/src/lib/mock-data/cache-stake-info.js
@@ -10,7 +10,6 @@ export default [
       },
       faults: 0,
       hardFaults: 0,
-      nonce: 0n,
       reward: 11022842680864n,
     },
   },
diff --git a/web-wallet/src/lib/mock-data/stakeInfo.js b/web-wallet/src/lib/mock-data/stakeInfo.js
index d1eecc439f..cba7daeebb 100644
--- a/web-wallet/src/lib/mock-data/stakeInfo.js
+++ b/web-wallet/src/lib/mock-data/stakeInfo.js
@@ -10,6 +10,5 @@ export default {
   },
   faults: 0,
   hardFaults: 0,
-  nonce: 0n,
   reward: 11022842680864n,
 };
diff --git a/web-wallet/src/lib/stores/walletStore.js b/web-wallet/src/lib/stores/walletStore.js
index 04917fc517..3424abc46e 100644
--- a/web-wallet/src/lib/stores/walletStore.js
+++ b/web-wallet/src/lib/stores/walletStore.js
@@ -44,7 +44,6 @@ const initialState = {
     amount: null,
     faults: 0,
     hardFaults: 0,
-    nonce: 0n,
     reward: 0n,
   },
   syncStatus: {
@@ -185,6 +184,18 @@ const clearLocalDataAndInit = (profileGenerator, syncFromBlock) =>
     return init(profileGenerator, syncFromBlock);
   });
 
+/** @type {WalletStoreServices["claimRewards"]} */
+const claimRewards = async (amount, gas) =>
+  sync()
+    .then(networkStore.connect)
+    .then((network) =>
+      network.execute(
+        bookkeeper.as(getCurrentProfile()).withdraw(amount).gas(gas)
+      )
+    )
+    .then(updateCacheAfterTransaction)
+    .then(passThruWithEffects(observeTxRemoval));
+
 /** @type {WalletStoreServices["getTransactionsHistory"]} */
 const getTransactionsHistory = async () => transactions;
 
@@ -403,18 +414,6 @@ const unstake = async (gas) =>
     .then(updateCacheAfterTransaction)
     .then(passThruWithEffects(observeTxRemoval));
 
-/** @type {WalletStoreServices["claimRewards"]} */
-const claimRewards = async (amount, gas) =>
-  sync()
-    .then(networkStore.connect)
-    .then((network) =>
-      network.execute(
-        bookkeeper.as(getCurrentProfile()).withdraw(amount).gas(gas)
-      )
-    )
-    .then(updateCacheAfterTransaction)
-    .then(passThruWithEffects(observeTxRemoval));
-
 /** @type {WalletStore} */
 export default {
   abortSync,
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/bookkeeper.js b/web-wallet/src/lib/vendor/w3sper.js/src/bookkeeper.js
index 73dbdb9b5d..979992194c 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/bookkeeper.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/bookkeeper.js
@@ -6,13 +6,13 @@
 // Copyright (c) DUSK NETWORK. All rights reserved.
 
 import * as ProtocolDriver from "../src/protocol-driver/mod.js";
-import { ProfileGenerator, Profile } from "./profile.js";
+import { Profile, ProfileGenerator } from "./profile.js";
 
 import {
-  Transfer,
-  UnshieldTransfer,
   ShieldTransfer,
   StakeTransfer,
+  Transfer,
+  UnshieldTransfer,
   UnstakeTransfer,
   WithdrawStakeRewardTransfer,
 } from "../src/transaction.js";
@@ -26,14 +26,9 @@ class BookEntry {
   }
 
   get info() {
-    const entry = this;
     return {
-      balance(type) {
-        return entry.bookkeeper.balance(entry.profile[type]);
-      },
-      stake() {
-        return entry.bookkeeper.stakeInfo(entry.profile.account);
-      },
+      balance: (type) => this.bookkeeper.balance(this.profile[type]),
+      stake: () => this.bookkeeper.stakeInfo(this.profile.account),
     };
   }
 
@@ -53,13 +48,17 @@ class BookEntry {
     return new StakeTransfer(this).amount(amount);
   }
 
-  unstake() {
-    return new UnstakeTransfer(this);
+  unstake(amount) {
+    return new UnstakeTransfer(this).amount(amount);
   }
 
   withdraw(amount) {
     return new WithdrawStakeRewardTransfer(this).amount(amount);
   }
+
+  topup(amount) {
+    return new StakeTransfer(this, { topup: true }).amount(amount);
+  }
 }
 
 export class Bookkeeper {
@@ -74,12 +73,13 @@ export class Bookkeeper {
     switch (type) {
       case "account":
         return await this.#treasury.account(identifier);
-      case "address":
+      case "address": {
         const notes = await this.#treasury.address(identifier);
         const seed = await ProfileGenerator.seedFrom(identifier);
         const index = +identifier;
 
         return ProtocolDriver.balance(seed, index, notes);
+      }
     }
   }
 
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/lux.js b/web-wallet/src/lib/vendor/w3sper.js/src/lux.js
new file mode 100644
index 0000000000..1a1cfb00b8
--- /dev/null
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/lux.js
@@ -0,0 +1,104 @@
+// @ts-nocheck
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) DUSK NETWORK. All rights reserved.
+
+/**
+ * A module for converting between the `BigInt` representation of Lux values
+ * and the human-readable Dusk format.
+ *
+ * The Dusk format represents Lux values as floating-point numbers with a fixed
+ * precision of 9 decimal places. This module ensures precise conversions and
+ * validates inputs for consistency and correctness.
+ *
+ * ## Notes on the Lux Representation
+ *
+ * Lux values are stored as unsigned 64-bit integers (`u64` in our contracts),
+ * meaning they cannot represent negative numbers. This restriction is inherent
+ * to their data type. Any attempt to format or parse negative numbers would
+ * violate this constraint and result in invalid operations.
+ *
+ * The unsigned 64-bit format also provides a higher maximum value
+ * (`18446744073709551615`) compared to signed 64-bit integers, which are
+ * capped at `9223372036854775807`. By restricting values to non-negative
+ *  numbers, the module adheres to the `u64` representation, ensuring accurate
+ * handling and avoiding unexpected behaviors or loss of precision.
+ *
+ * @module lux.js
+ */
+const DECIMALS = 9;
+const SCALE_FACTOR = 10n ** BigInt(DECIMALS);
+const FLOATING_POINT_REGEX = /^\d+(\.\d+)?$/;
+
+/**
+ * Converts a `BigInt` representation of a Lux value into a human-readable
+ * string formatted in Dusk.
+ *
+ * The resulting string represents the Lux value as a floating-point number
+ * with up to `DECIMALS` decimal places, omitting trailing zeros.
+ *
+ * @param {bigint} lux - The `BigInt` representation of the Lux value.
+ *
+ * @throws {TypeError} If the input is not a `BigInt`.
+ * @throws {RangeError} If the input is a negative value.
+
+ * @returns {string} A formatted string representing the Lux value in Dusk.
+ *
+ * @example usage
+ * ```js
+ * formatToDusk(11000000001n); // "11.000000001"
+ * formatToDusk(11000000000n); // "11"
+ *```
+ */
+export function formatToDusk(lux) {
+  if (typeof lux !== "bigint") {
+    throw new TypeError(
+      `Invalid Lux Type: Expected "bigint", but got "${typeof lux}".`
+    );
+  }
+
+  if (lux < 0n) {
+    throw new RangeError("Lux values cannot be negative.");
+  }
+
+  const unit = lux / SCALE_FACTOR;
+  let decimals = lux % SCALE_FACTOR;
+
+  if (decimals > 0) {
+    return `${unit}.${decimals.toString().padStart(DECIMALS, "0").replace(/0+$/, "")}`;
+  }
+
+  return unit.toString();
+}
+
+/**
+ * Parses a Dusk string into a `BigInt` representation of the value in Lux.
+ *
+ * The Dusk string must be a valid positive floating-point number representation
+ * (e.g., "11.000000001"), as Lux values are unsigned by definition.
+ * Trailing zeros in the fractional part are allowed, and the string will be
+ * interpreted with a fixed precision of `DECIMALS`.
+ *
+ * @param {string} dusk - The string formatted in Dusk to parse.
+ *
+ * @throws {TypeError} If the input is not a valid Dusk string.
+ *
+ * @returns {bigint} The `BigInt` representation of the Lux value.
+ *
+ * @example usage
+ * ```js
+ * parseFromDusk("11.000000001"); // 11000000001n
+ * parseFromDusk("11"); // 11000000000n
+ * ```
+ */
+export function parseFromDusk(dusk) {
+  if (typeof dusk !== "string" || !FLOATING_POINT_REGEX.test(dusk)) {
+    throw new TypeError(`Cannot parse "${dusk}" as a Lux value.`);
+  }
+
+  const [units, decimals = "0"] = dusk.split(".");
+
+  return BigInt(units) * SCALE_FACTOR + BigInt(decimals.padEnd(DECIMALS, "0"));
+}
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/mod.js b/web-wallet/src/lib/vendor/w3sper.js/src/mod.js
index 1697be4fce..fbc1354617 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/mod.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/mod.js
@@ -9,3 +9,5 @@ export * from "./network/mod.js";
 export * from "./profile.js";
 export * from "./bookkeeper.js";
 export * from "./transaction.js";
+export * as lux from "./lux.js";
+export { useAsProtocolDriver } from "./protocol-driver/mod.js";
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/network/mod.js b/web-wallet/src/lib/vendor/w3sper.js/src/network/mod.js
index a82aee26d4..98ec20b8b8 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/network/mod.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/network/mod.js
@@ -19,16 +19,6 @@ export { AddressSyncer } from "./syncer/address.js";
 export { AccountSyncer } from "./syncer/account.js";
 export { Bookmark } from "./bookmark.js";
 
-const abortable = (signal) =>
-  new Promise((resolve, reject) =>
-    signal?.aborted ? reject(signal.reason) : resolve(signal)
-  );
-
-const once = (target, topic) =>
-  new Promise((resolve) =>
-    target.addEventListener(topic, resolve, { once: true })
-  );
-
 export class Network {
   #rues;
   node;
@@ -84,8 +74,8 @@ export class Network {
   // I suspect is a GraphQL limitation. In the meantime we convert the `Number`
   // to a `BigInt` for consistency and future proof of the API's consumers.
   get blockHeight() {
-    return this.query("query { block(height: -1) { header { height } }}").then(
-      (body) => BigInt(body?.block?.header?.height ?? 0)
+    return this.query("block(height: -1) { header { height } }").then((body) =>
+      BigInt(body?.block?.header?.height ?? 0)
     );
   }
 
@@ -113,6 +103,8 @@ export class Network {
   }
 
   async query(gql, options = {}) {
+    gql = gql ? `query { ${gql} }` : "";
+
     const response = await this.#rues.scope("graphql").call.query(gql, options);
 
     switch (response.status) {
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/network/syncer/account.js b/web-wallet/src/lib/vendor/w3sper.js/src/network/syncer/account.js
index 191c316616..2a282d7ee0 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/network/syncer/account.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/network/syncer/account.js
@@ -30,16 +30,14 @@ class StakeAmount {
 }
 
 /**
- * Holds information about a user's stake, including amount, reward,
- * and a nonce to prevent repeat attacks. Also tracks faults.
+ * Holds information about a user's stake, including amount, reward
+ * and tracks faults.
  */
 class StakeInfo {
   /** @type {StakeAmount|null} */
   amount;
   /** @type {bigint} */
   reward;
-  /** @type {bigint} */
-  nonce;
   /** @type {number} */
   faults;
   /** @type {number} */
@@ -48,7 +46,6 @@ class StakeInfo {
   constructor() {
     this.amount = null;
     this.reward = 0n;
-    this.nonce = 0n;
     this.faults = 0;
     this.hardFaults = 0;
   }
@@ -78,9 +75,8 @@ class StakeInfo {
     }
 
     stakeInfo.reward = view.getBigUint64(40, true);
-    stakeInfo.nonce = view.getBigUint64(48, true);
-    stakeInfo.faults = view.getUint8(56);
-    stakeInfo.hardFaults = view.getUint8(57);
+    stakeInfo.faults = view.getUint8(48);
+    stakeInfo.hardFaults = view.getUint8(49);
 
     return Object.freeze(stakeInfo);
   }
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/protocol-driver/mod.js b/web-wallet/src/lib/vendor/w3sper.js/src/protocol-driver/mod.js
index ee23fa2f3d..1fd2f909cc 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/protocol-driver/mod.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/protocol-driver/mod.js
@@ -12,7 +12,7 @@ import { DriverError } from "./error.js";
 import * as DataBuffer from "./buffer.js";
 import { withAllocator } from "./alloc.js";
 
-const rng = () => new Uint8Array(32); //crypto.getRandomValues(new Uint8Array(32));
+const rng = () => crypto.getRandomValues(new Uint8Array(32));
 
 const uninit = Object.freeze([
   none`No Protocol Driver loaded yet. Call "load" first.`,
@@ -37,7 +37,6 @@ export function load(source, importsURL) {
   }
 
   // Parse known globals once.
-
   driverGlobals = protocolDriverModule.task(
     withAllocator(async function (_exports, allocator) {
       const { ptr, u32, u64 } = allocator.types;
@@ -52,14 +51,30 @@ export function load(source, importsURL) {
   )();
 }
 
-export function unload() {
+export async function unload() {
   if (protocolDriverModule instanceof none || driverGlobals instanceof none) {
-    return Promise.resolve();
-  } else {
-    return Promise.all([protocolDriverModule, driverGlobals]).then(() => {
-      [protocolDriverModule, driverGlobals] = uninit;
-    });
+    return;
   }
+
+  await Promise.all([protocolDriverModule, driverGlobals]);
+
+  [protocolDriverModule, driverGlobals] = uninit;
+}
+
+export function useAsProtocolDriver(source, importsURL) {
+  load(source, importsURL);
+
+  return {
+    cleanup() {
+      return unload();
+    },
+    then(onFulfilled, onRejected) {
+      return driverGlobals
+        .then(() => onFulfilled())
+        .catch(onRejected)
+        .finally(unload);
+    },
+  };
 }
 
 export async function opening(bytes) {
@@ -829,11 +844,6 @@ export const stake = async (info) =>
     ptr.nonce = await malloc(8);
     await memcpy(ptr.nonce, nonce);
 
-    const stake_nonce = new Uint8Array(8);
-    new DataView(stake_nonce.buffer).setBigUint64(0, info.stake_nonce, true);
-    ptr.stake_nonce = await malloc(8);
-    await memcpy(ptr.stake_nonce, stake_nonce);
-
     let tx = await malloc(4);
     let hash = await malloc(64);
 
@@ -845,7 +855,6 @@ export const stake = async (info) =>
       ptr.gas_price,
       ptr.nonce,
       info.chainId,
-      ptr.stake_nonce,
       tx,
       hash
     );
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/transaction.js b/web-wallet/src/lib/vendor/w3sper.js/src/transaction.js
index cf207c91fc..f71dcdd008 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/transaction.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/transaction.js
@@ -10,7 +10,7 @@ export const TRANSFER =
 
 import { AddressSyncer } from "./network/syncer/address.js";
 import * as ProtocolDriver from "./protocol-driver/mod.js";
-import { ProfileGenerator, Profile } from "./profile.js";
+import { Profile, ProfileGenerator } from "./profile.js";
 import * as base58 from "./encoders/b58.js";
 import { Gas } from "./gas.js";
 
@@ -53,7 +53,7 @@ export class Transfer extends BasicTransfer {
 
   to(value) {
     let builder;
-    let identifier = String(value);
+    const identifier = String(value);
     switch (ProfileGenerator.typeOf(identifier)) {
       case "account":
         builder = new AccountTransfer(this.bookentry);
@@ -118,7 +118,7 @@ class AccountTransfer extends Transfer {
 
     nonce += 1n;
 
-    let [buffer, hash] = await ProtocolDriver.moonlight({
+    const [buffer, hash] = await ProtocolDriver.moonlight({
       sender,
       receiver,
       transfer_value,
@@ -184,7 +184,7 @@ class AddressTransfer extends Transfer {
     const { chainId } = await network.node.info;
 
     // Create the unproven transaction
-    let [tx, circuits] = await ProtocolDriver.phoenix({
+    const [tx, circuits] = await ProtocolDriver.phoenix({
       sender,
       receiver,
       inputs,
@@ -246,7 +246,7 @@ export class UnshieldTransfer extends BasicTransfer {
     const { chainId } = await network.node.info;
 
     // Create the unproven transaction
-    let [tx, circuits] = await ProtocolDriver.unshield({
+    const [tx, circuits] = await ProtocolDriver.unshield({
       profile,
       inputs,
       openings,
@@ -280,7 +280,7 @@ export class ShieldTransfer extends BasicTransfer {
   async build(network) {
     const { attributes } = this;
     const { amount: allocate_value, gas } = attributes;
-    const { profile, bookkeeper } = this.bookentry;
+    const { profile } = this.bookentry;
 
     // Get the chain id from the network
     const { chainId } = await network.node.info;
@@ -290,7 +290,7 @@ export class ShieldTransfer extends BasicTransfer {
 
     nonce += 1n;
 
-    let [buffer, hash] = await ProtocolDriver.shield({
+    const [buffer, hash] = await ProtocolDriver.shield({
       profile,
       allocate_value,
       gas_limit: gas.limit,
@@ -308,35 +308,45 @@ export class ShieldTransfer extends BasicTransfer {
 }
 
 export class StakeTransfer extends BasicTransfer {
-  constructor(from) {
+  constructor(from, options = {}) {
     super(from);
+    this[_attributes].topup = Boolean(options.topup) || false;
   }
 
   async build(network) {
     const { attributes } = this;
-    const { amount: stake_value, gas } = attributes;
+    const { amount: stake_value, gas, topup: isTopup } = attributes;
     const { profile, bookkeeper } = this.bookentry;
 
     const minimumStake = await bookkeeper.minimumStake;
 
-    if (stake_value < minimumStake) {
-      throw new Error(`Stake value must be greater than ${minimumStake}`);
+    if (!isTopup && stake_value < minimumStake) {
+      throw new RangeError(
+        `Stake amount must be greater or equal than ${minimumStake}`
+      );
     }
 
     // Get the chain id from the network
     const { chainId } = await network.node.info;
 
-    // Obtain the nonces
+    // Obtain the infos
     let { nonce } = await this.bookentry.info.balance("account");
-    let { nonce: stake_nonce } = await this.bookentry.info.stake();
+    const stakeInfo = await this.bookentry.info.stake();
+    const hasStake = stakeInfo.amount !== null;
+
+    if (hasStake && !isTopup) {
+      throw new Error(
+        "Stake already exists. Use `topup` to add to the current stake"
+      );
+    } else if (!hasStake && isTopup) {
+      throw new Error("No stake to topup. Use `stake` to create a new stake");
+    }
 
     nonce += 1n;
-    stake_nonce += 1n;
 
-    let [buffer, hash] = await ProtocolDriver.stake({
+    const [buffer, hash] = await ProtocolDriver.stake({
       profile,
       stake_value,
-      stake_nonce,
       gas_limit: gas.limit,
       gas_price: gas.price,
       nonce,
@@ -358,7 +368,7 @@ export class UnstakeTransfer extends BasicTransfer {
 
   async build(network) {
     const { attributes } = this;
-    const { gas } = attributes;
+    const { gas, amount: unstake_amount } = attributes;
     const { profile } = this.bookentry;
 
     // Get the chain id from the network
@@ -368,13 +378,28 @@ export class UnstakeTransfer extends BasicTransfer {
     let { nonce } = await this.bookentry.info.balance("account");
 
     // Obtain the staked amount
-    let { amount } = await this.bookentry.info.stake();
+    const { amount } = await this.bookentry.info.stake();
+
+    const minimumStake = await this.bookentry.bookkeeper.minimumStake;
 
     nonce += 1n;
 
-    let [buffer, hash] = await ProtocolDriver.unstake({
+    const unstake_value =
+      typeof unstake_amount === "bigint" && unstake_amount < amount.total
+        ? unstake_amount
+        : amount.total;
+
+    const remainingStake = amount.total - unstake_value;
+
+    if (remainingStake > 0n && remainingStake < minimumStake) {
+      throw new RangeError(
+        `Remaining stake must be greater or equal than ${minimumStake}`
+      );
+    }
+
+    const [buffer, hash] = await ProtocolDriver.unstake({
       profile,
-      unstake_value: amount.total,
+      unstake_value,
       gas_limit: gas.limit,
       gas_price: gas.price,
       nonce,
@@ -406,23 +431,23 @@ export class WithdrawStakeRewardTransfer extends BasicTransfer {
     let { nonce } = await this.bookentry.info.balance("account");
 
     // Obtain the staked amount
-    let { reward } = await this.bookentry.info.stake();
+    const { reward } = await this.bookentry.info.stake();
 
     if (!reward) {
       throw new Error(`No stake available to withdraw the reward from`);
     } else if (reward_amount > reward) {
-      throw new Error(
+      throw new RangeError(
         `The withdrawn reward amount must be less or equal to ${reward}`
       );
     } else if (!reward_amount) {
-      throw new Error(
+      throw new RangeError(
         `Can't withdraw an empty reward amount. I mean, you could, but it would be pointless.`
       );
     }
 
     nonce += 1n;
 
-    let [buffer, hash] = await ProtocolDriver.withdraw({
+    const [buffer, hash] = await ProtocolDriver.withdraw({
       profile,
       reward_amount,
       gas_limit: gas.limit,
diff --git a/web-wallet/src/lib/vendor/wallet_core.wasm b/web-wallet/src/lib/vendor/wallet_core.wasm
index f14a61be3e..1a163027c0 100755
Binary files a/web-wallet/src/lib/vendor/wallet_core.wasm and b/web-wallet/src/lib/vendor/wallet_core.wasm differ
diff --git a/web-wallet/src/lib/wallet-cache/index.js b/web-wallet/src/lib/wallet-cache/index.js
index 638382daba..d9eca954a2 100644
--- a/web-wallet/src/lib/wallet-cache/index.js
+++ b/web-wallet/src/lib/wallet-cache/index.js
@@ -186,7 +186,6 @@ class WalletCache {
             amount: null,
             faults: 0,
             hardFaults: 0,
-            nonce: 0n,
             reward: 0n,
           }),
 


Test patch:
diff --git a/web-wallet/src/lib/stores/__tests__/walletStore.spec.js b/web-wallet/src/lib/stores/__tests__/walletStore.spec.js
index e802d591bb..2bb2787c57 100644
--- a/web-wallet/src/lib/stores/__tests__/walletStore.spec.js
+++ b/web-wallet/src/lib/stores/__tests__/walletStore.spec.js
@@ -121,7 +121,6 @@ describe("Wallet store", async () => {
       amount: null,
       faults: 0,
       hardFaults: 0,
-      nonce: 0n,
       reward: 0n,
     },
     syncStatus: {
@@ -323,7 +322,7 @@ describe("Wallet store", async () => {
     const setPendingNotesSpy = vi.spyOn(walletCache, "setPendingNoteInfo");
 
     /**
-     * @typedef { "shield" | "stake" | "transfer" | "unshield" | "unstake" | "claimRewards" } TransferMethod
+     * @typedef { "claimRewards" | "shield" | "stake" | "transfer" | "unshield" | "unstake" } TransferMethod
      */
 
     /**
@@ -365,13 +364,23 @@ describe("Wallet store", async () => {
           nonce: newNonce,
         });
 
-        expectedTx = isMoonlightTransfer
-          ? {
-              amount,
-              gas,
-              to: toMoonlight,
-            }
-          : { amount, gas };
+        if (isMoonlightTransfer) {
+          expectedTx = { amount, gas, to: toMoonlight };
+        } else {
+          switch (method) {
+            case "stake":
+              expectedTx = { amount, gas, topup: false };
+              break;
+
+            case "unstake":
+              expectedTx = { amount: undefined, gas };
+              break;
+
+            default:
+              expectedTx = { amount, gas };
+              break;
+          }
+        }
       }
 
       // @ts-ignore here args can't be inferred apparently
@@ -504,6 +513,10 @@ describe("Wallet store", async () => {
       setPendingNotesSpy.mockRestore();
     });
 
+    it("should expose a method to claim the rewards", async () => {
+      await walletStoreTransferCheck("claimRewards", [amount, gas]);
+    });
+
     it("should expose a method to shield a given amount from the unshielded account", async () => {
       await walletStoreTransferCheck("shield", [amount, gas]);
     });
@@ -524,8 +537,8 @@ describe("Wallet store", async () => {
       await walletStoreTransferCheck("unshield", [amount, gas]);
     });
 
-    it("should expose a method to claim the rewards", async () => {
-      await walletStoreTransferCheck("claimRewards", [amount, gas]);
+    it("should expose a method to unstake the staked amount", async () => {
+      await walletStoreTransferCheck("unstake", [gas]);
     });
   });
 
diff --git a/web-wallet/src/lib/wallet-cache/__tests__/index.spec.js b/web-wallet/src/lib/wallet-cache/__tests__/index.spec.js
index f779a2e0b9..e1f2ff84a0 100644
--- a/web-wallet/src/lib/wallet-cache/__tests__/index.spec.js
+++ b/web-wallet/src/lib/wallet-cache/__tests__/index.spec.js
@@ -198,7 +198,6 @@ describe("Wallet cache", () => {
         amount: null,
         faults: 0,
         hardFaults: 0,
-        nonce: 0n,
         reward: 0n,
       });
     });
diff --git a/web-wallet/src/lib/wallet-treasury/__tests__/index.spec.js b/web-wallet/src/lib/wallet-treasury/__tests__/index.spec.js
index a2be7eb3ef..e4d8dca448 100644
--- a/web-wallet/src/lib/wallet-treasury/__tests__/index.spec.js
+++ b/web-wallet/src/lib/wallet-treasury/__tests__/index.spec.js
@@ -145,7 +145,6 @@ describe("WalletTreasury", () => {
           }),
           faults: expect.any(Number),
           hardFaults: expect.any(Number),
-          nonce: expect.any(BigInt),
           reward: expect.any(BigInt),
         })
       );