diff --git a/web-wallet/src/__mocks__/AccountSyncer.js b/web-wallet/src/__mocks__/AccountSyncer.js
index 5987bf99da..7fe08f4532 100644
--- a/web-wallet/src/__mocks__/AccountSyncer.js
+++ b/web-wallet/src/__mocks__/AccountSyncer.js
@@ -1,5 +1,7 @@
 import { AccountSyncer } from "$lib/vendor/w3sper.js/src/network/syncer/account";
 
+import { stakeInfo } from "$lib/mock-data";
+
 class AccountSyncerMock extends AccountSyncer {
   /**
    * @param {import("$lib/vendor/w3sper.js/src/mod").Network} network
@@ -9,18 +11,23 @@ class AccountSyncerMock extends AccountSyncer {
   }
 
   /**
-   *
    * @param {Array<import("$lib/vendor/w3sper.js/src/mod").Profile>} profiles
-   * @param {Record<string, any>} [options={}]
    * @returns {Promise<AccountBalance[]>}
    */
-  // eslint-disable-next-line no-unused-vars
-  async balances(profiles, options = {}) {
+  async balances(profiles) {
     return Array(profiles.length).fill({
       nonce: 9876n,
       value: 12_345_000_000_000n,
     });
   }
+
+  /**
+   * @param {Array<import("$lib/vendor/w3sper.js/src/mod").Profile>} profiles
+   * @returns {Promise<StakeInfo[]>}
+   */
+  async stakes(profiles) {
+    return Array(profiles.length).fill(stakeInfo);
+  }
 }
 
 export default AccountSyncerMock;
diff --git a/web-wallet/src/__mocks__/mockedWalletStore.js b/web-wallet/src/__mocks__/mockedWalletStore.js
index e7f3baa6ee..ffa621ed58 100644
--- a/web-wallet/src/__mocks__/mockedWalletStore.js
+++ b/web-wallet/src/__mocks__/mockedWalletStore.js
@@ -1,5 +1,7 @@
 import { ProfileGenerator } from "$lib/vendor/w3sper.js/src/profile";
 
+import { stakeInfo } from "$lib/mock-data";
+
 import { mockReadableStore } from "$lib/dusk/test-helpers";
 
 const seed = new Uint8Array(64);
@@ -20,6 +22,7 @@ const content = {
   currentProfile,
   initialized: true,
   profiles,
+  stakeInfo,
   syncStatus: {
     error: null,
     from: 0n,
diff --git a/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte b/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte
index 5e7a2e7bce..e6e6ca6e24 100644
--- a/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte
+++ b/web-wallet/src/lib/containers/StakeContract/StakeContract.svelte
@@ -14,7 +14,7 @@
   import { mdiArrowLeft } from "@mdi/js";
   import { Gas } from "$lib/vendor/w3sper.js/src/mod";
 
-  import { createCurrencyFormatter } from "$lib/dusk/currency";
+  import { createCurrencyFormatter, luxToDusk } from "$lib/dusk/currency";
   import { getLastTransactionHash } from "$lib/transactions";
   import {
     gasStore,
@@ -35,6 +35,14 @@
 
   const gasLimits = $gasStore;
 
+  /**
+   * Temporary replacement for the old `walletStore.getStakeInfo`
+   * function.
+   * The UI needs to be updated to just use the `stakeInfo` property
+   * directly.
+   */
+  const getStakeInfo = async () => $walletStore.stakeInfo;
+
   const collectSettings = collect([
     pick([
       "gasLimit",
@@ -47,11 +55,11 @@
     getKey("minAllowedStake"),
   ]);
 
-  /** @type {Record<string, (info: WalletStakeInfo) => boolean>} */
+  /** @type {Record<string, (info: StakeInfo) => boolean>} */
   const disablingConditions = {
-    stake: (info) => info.has_staked,
-    unstake: (info) => !info.has_staked,
-    "withdraw-rewards": (info) => info.reward <= 0,
+    stake: (info) => !!info.amount,
+    unstake: (info) => !info.amount || info.amount.total === 0n,
+    "withdraw-rewards": (info) => info.reward <= 0n,
   };
 
   /** @type {Record<StakeType, (...args: any[]) => Promise<string>>} */
@@ -83,7 +91,7 @@
    * otherwise the descriptor takes precedence.
    *
    * @param {ContractOperation[]} operations
-   * @param {WalletStakeInfo} stakeInfo
+   * @param {StakeInfo} stakeInfo
    * @returns {ContractOperation[]}
    */
   const getOperations = (operations, stakeInfo) =>
@@ -96,27 +104,29 @@
     );
 
   /**
-   * @param {WalletStakeInfo} stakeInfo
+   * @param {StakeInfo} stakeInfo
    * @param {bigint} spendable
    * @returns {ContractStatus[]}
    */
   const getStatuses = (stakeInfo, spendable) => [
     {
       label: "Spendable",
-      value: duskFormatter(spendable),
+      value: duskFormatter(luxToDusk(spendable)),
     },
     {
       label: "Total Locked",
-      value: duskFormatter(stakeInfo.amount),
+      value: stakeInfo.amount
+        ? duskFormatter(luxToDusk(stakeInfo.amount.locked))
+        : "N/A",
     },
     {
       label: "Rewards",
-      value: duskFormatter(stakeInfo.reward),
+      value: duskFormatter(luxToDusk(stakeInfo.reward)),
     },
   ];
 
   /**
-   * @param {WalletStakeInfo} stakeInfo
+   * @param {StakeInfo} stakeInfo
    * @returns {(operation: ContractOperation) => ContractOperation}
    */
   const updateOperationDisabledStatus = (stakeInfo) => (operation) => ({
@@ -137,7 +147,7 @@
     gap="medium"
     errorMessage="Failed to retrieve stake info"
     errorVariant="details"
-    waitFor={walletStore.getStakeInfo()}
+    waitFor={getStakeInfo()}
   >
     <svelte:fragment slot="pending-content">
       {#if !syncStatus.isInProgress && !syncStatus.error}
@@ -161,9 +171,9 @@
           {minAllowedStake}
           on:operationChange
           on:suppressStakingNotice
-          rewards={stakeInfo.reward}
+          rewards={luxToDusk(stakeInfo.reward)}
           spendable={balance.shielded.spendable}
-          staked={stakeInfo.amount}
+          staked={stakeInfo.amount ? luxToDusk(stakeInfo.amount.total) : 0}
           {statuses}
           {hideStakingNotice}
         />
diff --git a/web-wallet/src/lib/mock-data/cache-stake-info.js b/web-wallet/src/lib/mock-data/cache-stake-info.js
new file mode 100644
index 0000000000..f6e78a4b6a
--- /dev/null
+++ b/web-wallet/src/lib/mock-data/cache-stake-info.js
@@ -0,0 +1,17 @@
+export default [
+  {
+    account: "",
+    stakeInfo: {
+      amount: {
+        eligibility: 0n,
+        locked: 0n,
+        total: 1000000000000n,
+        value: 1000000000000n,
+      },
+      faults: 0,
+      hardFaults: 0,
+      nonce: 0n,
+      reward: 11022842680864n,
+    },
+  },
+];
diff --git a/web-wallet/src/lib/mock-data/index.js b/web-wallet/src/lib/mock-data/index.js
index 912881ebc9..ef9a4aa77d 100644
--- a/web-wallet/src/lib/mock-data/index.js
+++ b/web-wallet/src/lib/mock-data/index.js
@@ -3,6 +3,7 @@ export { default as apiMarketData } from "./api-market-data.json";
 export { default as cacheBalances } from "./cache-balances";
 export { default as cachePendingNotesInfo } from "./cache-pending-notes-info";
 export { default as cacheSpentNotes } from "./cache-spent-notes";
+export { default as cacheStakeInfo } from "./cache-stake-info";
 export { default as cacheSyncInfo } from "./cache-sync-info";
 export { default as cacheUnspentNotes } from "./cache-unspent-notes";
 export { default as stakeInfo } from "./stakeInfo";
diff --git a/web-wallet/src/lib/mock-data/stakeInfo.js b/web-wallet/src/lib/mock-data/stakeInfo.js
index f29edd6446..d1eecc439f 100644
--- a/web-wallet/src/lib/mock-data/stakeInfo.js
+++ b/web-wallet/src/lib/mock-data/stakeInfo.js
@@ -1,9 +1,15 @@
-/* eslint-disable camelcase */
-
-/** @type {WalletStakeInfo} */
+/** @type {StakeInfo} */
 export default {
-  amount: 1000,
-  has_key: true,
-  has_staked: true,
-  reward: 500,
+  amount: {
+    eligibility: 0n,
+    locked: 0n,
+    get total() {
+      return this.value + this.locked;
+    },
+    value: 1000000000000n,
+  },
+  faults: 0,
+  hardFaults: 0,
+  nonce: 0n,
+  reward: 11022842680864n,
 };
diff --git a/web-wallet/src/lib/stores/__tests__/walletStore.spec.js b/web-wallet/src/lib/stores/__tests__/walletStore.spec.js
index 11222bddae..991afe15ce 100644
--- a/web-wallet/src/lib/stores/__tests__/walletStore.spec.js
+++ b/web-wallet/src/lib/stores/__tests__/walletStore.spec.js
@@ -16,6 +16,8 @@ import {
 } from "$lib/vendor/w3sper.js/src/mod";
 import { generateMnemonic } from "bip39";
 
+import { stakeInfo } from "$lib/mock-data";
+
 import walletCache from "$lib/wallet-cache";
 import WalletTreasury from "$lib/wallet-treasury";
 import { getSeedFromMnemonic } from "$lib/wallet";
@@ -36,6 +38,20 @@ describe("Wallet store", async () => {
       value: 4n,
     },
   };
+  const cachedStakeInfo = {
+    amount: {
+      eligibility: 123n,
+      locked: 456n,
+      get total() {
+        return this.value + this.locked;
+      },
+      value: 100n,
+    },
+    faults: 10,
+    hardFaults: 2,
+    nonce: 5n,
+    reward: 56789n,
+  };
   const shielded = {
     spendable: 400000000000000n,
     value: 1026179647718621n,
@@ -56,6 +72,9 @@ describe("Wallet store", async () => {
         ? shielded
         : unshielded;
     });
+  const stakeInfoSpy = vi
+    .spyOn(Bookkeeper.prototype, "stakeInfo")
+    .mockImplementation(async () => stakeInfo);
 
   const getCachedBalanceSpy = vi
     .spyOn(walletCache, "getBalanceInfo")
@@ -63,6 +82,12 @@ describe("Wallet store", async () => {
   const setCachedBalanceSpy = vi
     .spyOn(walletCache, "setBalanceInfo")
     .mockResolvedValue(undefined);
+  const getCachedStakeInfoSpy = vi
+    .spyOn(walletCache, "getStakeInfo")
+    .mockResolvedValue(cachedStakeInfo);
+  const setCachedStakeInfoSpy = vi
+    .spyOn(walletCache, "setStakeInfo")
+    .mockResolvedValue(undefined);
   const setLastBlockHeightSpy = vi.spyOn(walletCache, "setLastBlockHeight");
   const setProfilesSpy = vi.spyOn(WalletTreasury.prototype, "setProfiles");
   const treasuryUpdateSpy = vi.spyOn(WalletTreasury.prototype, "update");
@@ -85,6 +110,13 @@ describe("Wallet store", async () => {
     currentProfile: null,
     initialized: false,
     profiles: [],
+    stakeInfo: {
+      amount: null,
+      faults: 0,
+      hardFaults: 0,
+      nonce: 0n,
+      reward: 0n,
+    },
     syncStatus: {
       error: null,
       from: 0n,
@@ -100,31 +132,18 @@ describe("Wallet store", async () => {
     currentProfile: defaultProfile,
     initialized: true,
     profiles: [defaultProfile],
+    stakeInfo,
   };
 
   beforeEach(async () => {
     await vi.runOnlyPendingTimersAsync();
     vi.clearAllTimers();
-    setTimeoutSpy.mockClear();
-    clearTimeoutSpy.mockClear();
-    abortControllerSpy.mockClear();
-    setLastBlockHeightSpy.mockClear();
-    setCachedBalanceSpy.mockClear();
-    setProfilesSpy.mockClear();
-    treasuryUpdateSpy.mockClear();
+    vi.clearAllMocks();
   });
 
   afterAll(() => {
     vi.useRealTimers();
-    setTimeoutSpy.mockRestore();
-    clearTimeoutSpy.mockRestore();
-    abortControllerSpy.mockRestore();
-    setLastBlockHeightSpy.mockRestore();
-    balanceSpy.mockRestore();
-    getCachedBalanceSpy.mockRestore();
-    setCachedBalanceSpy.mockRestore();
-    setProfilesSpy.mockRestore();
-    treasuryUpdateSpy.mockRestore();
+    vi.restoreAllMocks();
   });
 
   describe("Initialization and sync", () => {
@@ -137,6 +156,7 @@ describe("Wallet store", async () => {
         currentProfile: defaultProfile,
         initialized: true,
         profiles: [defaultProfile],
+        stakeInfo: cachedStakeInfo,
         syncStatus: {
           error: null,
           from: 0n,
@@ -146,6 +166,15 @@ describe("Wallet store", async () => {
         },
       });
 
+      expect(getCachedBalanceSpy).toHaveBeenCalledTimes(1);
+      expect(getCachedBalanceSpy).toHaveBeenCalledWith(
+        defaultProfile.address.toString()
+      );
+      expect(getCachedStakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(getCachedStakeInfoSpy).toHaveBeenCalledWith(
+        defaultProfile.account.toString()
+      );
+
       await vi.advanceTimersByTimeAsync(AUTO_SYNC_INTERVAL - 1);
 
       expect(get(walletStore)).toStrictEqual(initializedStore);
@@ -156,6 +185,11 @@ describe("Wallet store", async () => {
       );
       expect(treasuryUpdateSpy).toHaveBeenCalledTimes(1);
       expect(setLastBlockHeightSpy).toHaveBeenCalledTimes(1);
+      expect(balanceSpy).toHaveBeenCalledTimes(2);
+      expect(balanceSpy).toHaveBeenNthCalledWith(1, defaultProfile.address);
+      expect(balanceSpy).toHaveBeenNthCalledWith(2, defaultProfile.account);
+      expect(stakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(stakeInfoSpy).toHaveBeenCalledWith(defaultProfile.account);
       expect(setLastBlockHeightSpy).toHaveBeenCalledWith(expect.any(BigInt));
       expect(setLastBlockHeightSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
         treasuryUpdateSpy.mock.invocationCallOrder[0]
@@ -163,9 +197,9 @@ describe("Wallet store", async () => {
       expect(balanceSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
         treasuryUpdateSpy.mock.invocationCallOrder[0]
       );
-      expect(balanceSpy).toHaveBeenCalledTimes(2);
-      expect(balanceSpy).toHaveBeenNthCalledWith(1, defaultProfile.address);
-      expect(balanceSpy).toHaveBeenNthCalledWith(2, defaultProfile.account);
+      expect(stakeInfoSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
+        treasuryUpdateSpy.mock.invocationCallOrder[0]
+      );
       expect(setCachedBalanceSpy).toHaveBeenCalledTimes(1);
       expect(setCachedBalanceSpy).toHaveBeenCalledWith(
         defaultProfile.address.toString(),
@@ -174,9 +208,17 @@ describe("Wallet store", async () => {
           unshielded: await balanceSpy.mock.results[1].value,
         }
       );
+      expect(setCachedStakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(setCachedStakeInfoSpy).toHaveBeenCalledWith(
+        defaultProfile.account.toString(),
+        await stakeInfoSpy.mock.results[0].value
+      );
       expect(setCachedBalanceSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
         balanceSpy.mock.invocationCallOrder[1]
       );
+      expect(setCachedStakeInfoSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
+        stakeInfoSpy.mock.invocationCallOrder[0]
+      );
       expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
       expect(setTimeoutSpy).toHaveBeenCalledTimes(1);
       expect(clearTimeoutSpy.mock.invocationCallOrder[0]).toBeLessThan(
@@ -291,7 +333,9 @@ describe("Wallet store", async () => {
 
       treasuryUpdateSpy.mockClear();
       balanceSpy.mockClear();
+      stakeInfoSpy.mockClear();
       setCachedBalanceSpy.mockClear();
+      setCachedStakeInfoSpy.mockClear();
     });
 
     afterEach(async () => {
@@ -342,6 +386,8 @@ describe("Wallet store", async () => {
       expect(balanceSpy).toHaveBeenCalledTimes(2);
       expect(balanceSpy).toHaveBeenNthCalledWith(1, newProfile.address);
       expect(balanceSpy).toHaveBeenNthCalledWith(2, newProfile.account);
+      expect(stakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(stakeInfoSpy).toHaveBeenCalledWith(newProfile.account);
     });
 
     it("should expose a method to set the current profile and update the balance afterwards", async () => {
@@ -371,6 +417,8 @@ describe("Wallet store", async () => {
       expect(balanceSpy).toHaveBeenCalledTimes(2);
       expect(balanceSpy).toHaveBeenNthCalledWith(1, fakeExtraProfile.address);
       expect(balanceSpy).toHaveBeenNthCalledWith(2, fakeExtraProfile.account);
+      expect(stakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(stakeInfoSpy).toHaveBeenCalledWith(fakeExtraProfile.account);
       expect(setCachedBalanceSpy).toHaveBeenCalledTimes(1);
       expect(setCachedBalanceSpy).toHaveBeenCalledWith(
         fakeExtraProfile.address.toString(),
@@ -379,9 +427,17 @@ describe("Wallet store", async () => {
           unshielded: await balanceSpy.mock.results[1].value,
         }
       );
+      expect(setCachedStakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(setCachedStakeInfoSpy).toHaveBeenCalledWith(
+        fakeExtraProfile.account.toString(),
+        await stakeInfoSpy.mock.results[0].value
+      );
       expect(setCachedBalanceSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
         balanceSpy.mock.invocationCallOrder[1]
       );
+      expect(setCachedStakeInfoSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
+        stakeInfoSpy.mock.invocationCallOrder[0]
+      );
     });
 
     it("should reject with an error if the profile is not in the known list", async () => {
@@ -468,6 +524,9 @@ describe("Wallet store", async () => {
       // but the balance is not updated yet
       expect(balanceSpy).not.toHaveBeenCalled();
 
+      // and neither the stake info
+      expect(stakeInfoSpy).not.toHaveBeenCalled();
+
       expect(treasuryUpdateSpy.mock.invocationCallOrder[0]).toBeLessThan(
         executeSpy.mock.invocationCallOrder[0]
       );
@@ -491,6 +550,8 @@ describe("Wallet store", async () => {
       expect(balanceSpy).toHaveBeenCalledTimes(2);
       expect(balanceSpy).toHaveBeenNthCalledWith(1, defaultProfile.address);
       expect(balanceSpy).toHaveBeenNthCalledWith(2, defaultProfile.account);
+      expect(stakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(stakeInfoSpy).toHaveBeenCalledWith(defaultProfile.account);
       expect(balanceSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
         treasuryUpdateSpy.mock.invocationCallOrder[1]
       );
@@ -505,9 +566,17 @@ describe("Wallet store", async () => {
           unshielded: await balanceSpy.mock.results[1].value,
         }
       );
+      expect(setCachedStakeInfoSpy).toHaveBeenCalledTimes(1);
+      expect(setCachedStakeInfoSpy).toHaveBeenCalledWith(
+        defaultProfile.account.toString(),
+        await stakeInfoSpy.mock.results[0].value
+      );
       expect(setCachedBalanceSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
         balanceSpy.mock.invocationCallOrder[1]
       );
+      expect(setCachedStakeInfoSpy.mock.invocationCallOrder[0]).toBeGreaterThan(
+        stakeInfoSpy.mock.invocationCallOrder[0]
+      );
 
       vi.useFakeTimers();
     });
@@ -590,6 +659,9 @@ describe("Wallet store", async () => {
       // but the balance is not updated yet
       expect(balanceSpy).not.toHaveBeenCalled();
 
+      // and neither the stake info
+      expect(stakeInfoSpy).not.toHaveBeenCalled();
+
       expect(treasuryUpdateSpy.mock.invocationCallOrder[0]).toBeLessThan(
         executeSpy.mock.invocationCallOrder[0]
       );
diff --git a/web-wallet/src/lib/stores/stores.d.ts b/web-wallet/src/lib/stores/stores.d.ts
index 2f48448fa1..d7d2ccf7ad 100644
--- a/web-wallet/src/lib/stores/stores.d.ts
+++ b/web-wallet/src/lib/stores/stores.d.ts
@@ -84,6 +84,7 @@ type WalletStoreContent = {
   currentProfile: import("$lib/vendor/w3sper.js/src/mod").Profile | null;
   initialized: boolean;
   profiles: Array<import("$lib/vendor/w3sper.js/src/mod").Profile>;
+  stakeInfo: StakeInfo;
   syncStatus: {
     from: bigint;
     isInProgress: boolean;
@@ -103,8 +104,6 @@ type WalletStoreServices = {
     syncFromBlock?: bigint
   ) => Promise<void>;
 
-  getStakeInfo: () => Promise<any>;
-
   getTransactionsHistory: () => Promise<any>;
 
   init: (
diff --git a/web-wallet/src/lib/stores/walletStore.js b/web-wallet/src/lib/stores/walletStore.js
index 26e649294a..7728a9635e 100644
--- a/web-wallet/src/lib/stores/walletStore.js
+++ b/web-wallet/src/lib/stores/walletStore.js
@@ -39,6 +39,13 @@ const initialState = {
   currentProfile: null,
   initialized: false,
   profiles: [],
+  stakeInfo: {
+    amount: null,
+    faults: 0,
+    hardFaults: 0,
+    nonce: 0n,
+    reward: 0n,
+  },
   syncStatus: {
     error: null,
     from: 0n,
@@ -66,7 +73,7 @@ const observeTxRemoval = (txInfo) => {
       .withId(txInfo.hash)
       .once.removed()
       .then(() => sync())
-      .finally(updateBalance)
+      .finally(updateStaticInfo)
   );
 };
 
@@ -133,6 +140,33 @@ const updateBalance = async () => {
   }));
 };
 
+/** @type {() => Promise<void>} */
+const updateStakeInfo = async () => {
+  const { currentProfile } = get(walletStore);
+
+  if (!currentProfile) {
+    return;
+  }
+
+  const stakeInfo = await bookkeeper.stakeInfo(currentProfile.account);
+
+  /**
+   * We ignore the error as the cached stake info is only
+   * a nice to have for the user.
+   */
+  await walletCache
+    .setStakeInfo(currentProfile.account.toString(), stakeInfo)
+    .catch(() => {});
+
+  update((currentStore) => ({
+    ...currentStore,
+    stakeInfo,
+  }));
+};
+
+const updateStaticInfo = () =>
+  Promise.allSettled([updateBalance(), updateStakeInfo()]);
+
 /** @type {WalletStoreServices["abortSync"]} */
 const abortSync = () => {
   window.clearTimeout(autoSyncId);
@@ -153,9 +187,6 @@ const clearLocalDataAndInit = (profileGenerator, syncFromBlock) =>
     return init(profileGenerator, syncFromBlock);
   });
 
-/** @type {WalletStoreServices["getStakeInfo"]} */
-const getStakeInfo = async () => ({ amount: 0, reward: 0 });
-
 /** @type {WalletStoreServices["getTransactionsHistory"]} */
 const getTransactionsHistory = async () => transactions;
 
@@ -164,6 +195,9 @@ async function init(profileGenerator, syncFromBlock) {
   const currentProfile = await profileGenerator.default;
   const currentAddress = currentProfile.address.toString();
   const cachedBalance = await walletCache.getBalanceInfo(currentAddress);
+  const cachedStakeInfo = await walletCache.getStakeInfo(
+    currentProfile.account.toString()
+  );
 
   treasury.setProfiles([currentProfile]);
 
@@ -173,13 +207,14 @@ async function init(profileGenerator, syncFromBlock) {
     currentProfile,
     initialized: true,
     profiles: [currentProfile],
+    stakeInfo: cachedStakeInfo,
   });
 
   sync(syncFromBlock)
     .then(() => {
       settingsStore.update(setKey("userId", currentAddress));
     })
-    .finally(updateBalance);
+    .finally(updateStaticInfo);
 }
 
 /** @type {WalletStoreServices["reset"]} */
@@ -194,7 +229,9 @@ async function setCurrentProfile(profile) {
 
   return store.profiles.includes(profile)
     ? Promise.resolve(set({ ...store, currentProfile: profile })).then(
-        updateBalance
+        async () => {
+          await updateStaticInfo();
+        }
       )
     : Promise.reject(
         new Error("The received profile is not in the known list")
@@ -282,7 +319,7 @@ async function sync(fromBlock) {
       .then(() => {
         window.clearTimeout(autoSyncId);
         autoSyncId = window.setTimeout(() => {
-          sync().finally(updateBalance);
+          sync().finally(updateStaticInfo);
         }, AUTO_SYNC_INTERVAL);
       })
       .catch((error) => {
@@ -361,7 +398,6 @@ export default {
   abortSync,
   clearLocalData,
   clearLocalDataAndInit,
-  getStakeInfo,
   getTransactionsHistory,
   init,
   reset,
diff --git a/web-wallet/src/lib/test-helpers/__tests__/fillCacheDatabase.spec.js b/web-wallet/src/lib/test-helpers/__tests__/fillCacheDatabase.spec.js
index 6193c274bc..d1b95661a9 100644
--- a/web-wallet/src/lib/test-helpers/__tests__/fillCacheDatabase.spec.js
+++ b/web-wallet/src/lib/test-helpers/__tests__/fillCacheDatabase.spec.js
@@ -1,9 +1,11 @@
 import { beforeEach, describe, expect, it } from "vitest";
-import { sortWith } from "lamb";
+import { getKey, skipIn, sortWith } from "lamb";
 
 import {
+  cacheBalances,
   cachePendingNotesInfo,
   cacheSpentNotes,
+  cacheStakeInfo,
   cacheSyncInfo,
   cacheUnspentNotes,
 } from "$lib/mock-data";
@@ -23,6 +25,9 @@ const sortByDbNullifier = sortWith([
   ),
 ]);
 
+const sortByAccount = sortWith([getKey("account")]);
+const sortByAddress = sortWith([getKey("address")]);
+
 /** @type {(entry: WalletCacheNote) => WalletCacheDbNote} */
 const toDbNote = (entry) => ({
   ...entry,
@@ -52,12 +57,26 @@ describe("fillCacheDatabase", () => {
 
     await db.open();
 
+    await expect(
+      db.table("balancesInfo").toArray().then(sortByAddress)
+    ).resolves.toStrictEqual(sortByAddress(cacheBalances));
     await expect(
       db.table("pendingNotesInfo").toArray().then(sortByDbNullifier)
     ).resolves.toStrictEqual(expectedPendingNotesInfo);
     await expect(
       db.table("spentNotes").toArray().then(sortByDbNullifier)
     ).resolves.toStrictEqual(expectedSpentNotes);
+    await expect(
+      db.table("stakeInfo").toArray().then(sortByAccount)
+    ).resolves.toStrictEqual(
+      sortByAccount(cacheStakeInfo).map((entry) => ({
+        ...entry,
+        stakeInfo: {
+          ...entry.stakeInfo,
+          amount: skipIn(entry.stakeInfo.amount, ["total"]),
+        },
+      }))
+    );
     await expect(db.table("syncInfo").toArray()).resolves.toStrictEqual(
       cacheSyncInfo
     );
diff --git a/web-wallet/src/lib/test-helpers/__tests__/getCacheDatabase.spec.js b/web-wallet/src/lib/test-helpers/__tests__/getCacheDatabase.spec.js
index 2deeb64ec7..8f998ffa47 100644
--- a/web-wallet/src/lib/test-helpers/__tests__/getCacheDatabase.spec.js
+++ b/web-wallet/src/lib/test-helpers/__tests__/getCacheDatabase.spec.js
@@ -16,6 +16,7 @@ describe("getCacheDatabase", () => {
         "spentNotes",
         "syncInfo",
         "unspentNotes",
+        "stakeInfo",
       ]
     `);
 
diff --git a/web-wallet/src/lib/test-helpers/fillCacheDatabase.js b/web-wallet/src/lib/test-helpers/fillCacheDatabase.js
index 1eadf1931c..48c941016b 100644
--- a/web-wallet/src/lib/test-helpers/fillCacheDatabase.js
+++ b/web-wallet/src/lib/test-helpers/fillCacheDatabase.js
@@ -1,10 +1,11 @@
-import { mapWith } from "lamb";
+import { mapWith, skipIn } from "lamb";
 import { getCacheDatabase } from ".";
 
 import {
   cacheBalances,
   cachePendingNotesInfo,
   cacheSpentNotes,
+  cacheStakeInfo,
   cacheSyncInfo,
   cacheUnspentNotes,
 } from "$lib/mock-data";
@@ -27,6 +28,23 @@ const fixNotes = mapWith((record) => ({
   nullifier: record.nullifier.buffer,
 }));
 
+/**
+ * In IndexedDB objects with a getter will be
+ * written without the getter.
+ *
+ * In `fake-indexeddb` apparently the getter is
+ * written as a normal prop.
+ *
+ * Hence we remove it to simulate the real situation.
+ */
+const fixStakeInfo = mapWith((entry) => ({
+  ...entry,
+  stakeInfo: {
+    ...entry.stakeInfo,
+    amount: skipIn(entry.stakeInfo.amount, ["total"]),
+  },
+}));
+
 /** @type {() => Promise<void>} */
 async function fillCacheDatabase() {
   const db = getCacheDatabase();
@@ -40,6 +58,7 @@ async function fillCacheDatabase() {
         "balancesInfo",
         "pendingNotesInfo",
         "spentNotes",
+        "stakeInfo",
         "syncInfo",
         "unspentNotes",
       ],
@@ -49,6 +68,7 @@ async function fillCacheDatabase() {
           .table("pendingNotesInfo")
           .bulkPut(fixPending(cachePendingNotesInfo));
         await db.table("spentNotes").bulkPut(fixNotes(cacheSpentNotes));
+        await db.table("stakeInfo").bulkPut(fixStakeInfo(cacheStakeInfo));
         await db.table("syncInfo").bulkPut(cacheSyncInfo);
         await db.table("unspentNotes").bulkPut(fixNotes(cacheUnspentNotes));
       }
diff --git a/web-wallet/src/lib/test-helpers/getCacheDatabase.js b/web-wallet/src/lib/test-helpers/getCacheDatabase.js
index c2c4de3cd3..c6791b59f9 100644
--- a/web-wallet/src/lib/test-helpers/getCacheDatabase.js
+++ b/web-wallet/src/lib/test-helpers/getCacheDatabase.js
@@ -12,6 +12,15 @@ function getCacheDatabase() {
     unspentNotes: "nullifier,address",
   });
 
+  db.version(2).stores({
+    balancesInfo: "address",
+    pendingNotesInfo: "nullifier,txId",
+    spentNotes: "nullifier,address",
+    stakeInfo: "account",
+    syncInfo: "++",
+    unspentNotes: "nullifier,address",
+  });
+
   return db;
 }
 
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 648a4c1a32..0cf7febf51 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/bookkeeper.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/bookkeeper.js
@@ -22,10 +22,14 @@ class BookEntry {
     Object.freeze(this);
   }
 
-  async balance(type) {
+  balance(type) {
     return this.bookkeeper.balance(this.profile[type]);
   }
 
+  stakeInfo() {
+    return this.bookkeeper.stakeInfo(this.profile.account);
+  }
+
   transfer(amount) {
     return new Transfer(this).amount(amount);
   }
@@ -60,6 +64,15 @@ export class Bookkeeper {
     }
   }
 
+  stakeInfo(identifier) {
+    const type = ProfileGenerator.typeOf(String(identifier));
+    if (type !== "account") {
+      throw new TypeError("Only accounts can stake");
+    }
+
+    return this.#treasury.stakeInfo(identifier);
+  }
+
   async pick(identifier, amount) {
     const notes = await this.#treasury.address(identifier);
     const seed = await ProfileGenerator.seedFrom(identifier);
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/encoders/b16.js b/web-wallet/src/lib/vendor/w3sper.js/src/encoders/b16.js
new file mode 100644
index 0000000000..ea47f5ee33
--- /dev/null
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/encoders/b16.js
@@ -0,0 +1,26 @@
+// @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.
+
+export const encode = (buffer) =>
+  Array.from(buffer)
+    .map((byte) => byte.toString(16).padStart(2, "0"))
+    .join("");
+
+export function decode(string) {
+  // Check if the string has an even length and contains only valid hex characters
+  if (string.length % 2 !== 0 || !/^[\da-fA-F]+$/.test(string)) {
+    return null;
+  }
+
+  const buffer = new Uint8Array(string.length / 2);
+
+  for (let i = 0; i < string.length; i += 2) {
+    buffer[i / 2] = parseInt(string.slice(i, i + 2), 16);
+  }
+
+  return buffer;
+}
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/b58.js b/web-wallet/src/lib/vendor/w3sper.js/src/encoders/b58.js
similarity index 100%
rename from web-wallet/src/lib/vendor/w3sper.js/src/b58.js
rename to web-wallet/src/lib/vendor/w3sper.js/src/encoders/b58.js
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/network/gas.js b/web-wallet/src/lib/vendor/w3sper.js/src/gas.js
similarity index 100%
rename from web-wallet/src/lib/vendor/w3sper.js/src/network/gas.js
rename to web-wallet/src/lib/vendor/w3sper.js/src/gas.js
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/network/components/contracts.js b/web-wallet/src/lib/vendor/w3sper.js/src/network/components/contracts.js
index 51177c2d43..f2c4ff6689 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/network/components/contracts.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/network/components/contracts.js
@@ -35,4 +35,10 @@ export class Contracts {
       "0100000000000000000000000000000000000000000000000000000000000000"
     );
   }
+
+  get stakeContract() {
+    return this.withId(
+      "0200000000000000000000000000000000000000000000000000000000000000"
+    );
+  }
 }
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/network/components/transactions.js b/web-wallet/src/lib/vendor/w3sper.js/src/network/components/transactions.js
index 241a4cf097..039ddf6d4f 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/network/components/transactions.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/network/components/transactions.js
@@ -5,11 +5,40 @@
 //
 // Copyright (c) DUSK NETWORK. All rights reserved.
 
-export class Transactions {
+import { Gas } from "../../gas.js";
+import { RuesScope } from "../../rues/scope.js";
+import { RuesEvent } from "../../rues/event.js";
+import * as base16 from "../../encoders/b16.js";
+
+class TransactionExecutedEvent extends RuesEvent {
+  constructor(type) {
+    super(type);
+  }
+
+  get gasPaid() {
+    return new Gas({
+      limit: this.payload["gas_spent"],
+      price: this.payload.inner.fee["gas_price"],
+    }).total;
+  }
+
+  memo(options = {}) {
+    const buffer = base16.decode(this.payload.inner.memo);
+
+    if (options.as === "string") {
+      return new TextDecoder().decode(buffer);
+    }
+
+    return buffer;
+  }
+}
+
+export class Transactions extends RuesScope {
   #scope = null;
 
   constructor(rues) {
-    this.#scope = rues.scope("transactions");
+    super("transactions");
+    this.#scope = rues.scope(this);
   }
 
   preverify(tx) {
@@ -45,4 +74,13 @@ export class Transactions {
   withId(id) {
     return this.#scope.withId(id);
   }
+
+  eventFrom(ruesEvent) {
+    switch (ruesEvent.origin.topic) {
+      case "executed":
+        return TransactionExecutedEvent.from(ruesEvent);
+    }
+
+    return ruesEvent;
+  }
 }
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 d7dd68abed..1f2484e0ed 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
@@ -12,7 +12,7 @@ import { Node } from "./components/node.js";
 import { Blocks } from "./components/blocks.js";
 import { Transactions } from "./components/transactions.js";
 import { Contracts } from "./components/contracts.js";
-import { Gas } from "./gas.js";
+import { Gas } from "../gas.js";
 
 export { Gas };
 export { AddressSyncer } from "./syncer/address.js";
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 4702b79d1f..191c316616 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
@@ -6,8 +6,93 @@
 // Copyright (c) DUSK NETWORK. All rights reserved.
 
 import * as ProtocolDriver from "../../protocol-driver/mod.js";
-import * as base58 from "../../b58.js";
+import * as base58 from "../../encoders/b58.js";
 
+/**
+ * Represents the value staked, locked, and eligibility of a stake.
+ */
+class StakeAmount {
+  /** @type {bigint} */
+  value = 0n;
+  /** @type {bigint} */
+  locked = 0n;
+  /** @type {bigint} */
+  eligibility = 0n;
+
+  /**
+   * Returns the total amount of staked value, including locked value.
+   *
+   * @returns {bigint} Total staked amount.
+   */
+  get total() {
+    return this.value + this.locked;
+  }
+}
+
+/**
+ * Holds information about a user's stake, including amount, reward,
+ * and a nonce to prevent repeat attacks. Also tracks faults.
+ */
+class StakeInfo {
+  /** @type {StakeAmount|null} */
+  amount;
+  /** @type {bigint} */
+  reward;
+  /** @type {bigint} */
+  nonce;
+  /** @type {number} */
+  faults;
+  /** @type {number} */
+  hardFaults;
+
+  constructor() {
+    this.amount = null;
+    this.reward = 0n;
+    this.nonce = 0n;
+    this.faults = 0;
+    this.hardFaults = 0;
+  }
+
+  /**
+   * Parses a buffer into a {StakeInfo} instance.
+   *
+   * @param {ArrayBuffer} buffer - The buffer containing stake data.
+   * @returns {StakeInfo} The parsed {StakeInfo} instance.
+   */
+  static parse(buffer) {
+    const view = new DataView(buffer);
+    const stakeInfo = new StakeInfo();
+    const hasStake = view.getUint8(0) === 1;
+
+    if (!hasStake) {
+      return Object.freeze(stakeInfo);
+    }
+
+    const hasStakeAmount = view.getUint8(8) === 1;
+
+    if (hasStakeAmount) {
+      stakeInfo.amount = new StakeAmount();
+      stakeInfo.amount.value = view.getBigUint64(16, true);
+      stakeInfo.amount.locked = view.getBigUint64(24, true);
+      stakeInfo.amount.eligibility = view.getBigUint64(32, true);
+    }
+
+    stakeInfo.reward = view.getBigUint64(40, true);
+    stakeInfo.nonce = view.getBigUint64(48, true);
+    stakeInfo.faults = view.getUint8(56);
+    stakeInfo.hardFaults = view.getUint8(57);
+
+    return Object.freeze(stakeInfo);
+  }
+}
+
+/**
+ * Converts a resource, either a string or an object with an account,
+ * into an account buffer if it has a byteLength of 96.
+ *
+ * @param {Object|string} resource - The resource to convert.
+ * @returns {ArrayBuffer|Object|string} The account buffer or the resource.
+ */
 function intoAccount(resource) {
   if (resource?.account?.valueOf()?.byteLength === 96) {
     return resource.account;
@@ -21,31 +106,82 @@ function intoAccount(resource) {
   return resource;
 }
 
+/**
+ * Converts account profiles into raw representations.
+ *
+ * @param {Array<Object>} profiles - Array of profile objects.
+ * @returns {Promise<Array<Uint8Array>>} The raw account buffers.
+ */
+const accountsIntoRaw = (profiles) =>
+  ProtocolDriver.accountsIntoRaw(profiles.map(intoAccount));
+
+/**
+ * Parses a buffer to extract account balance information.
+ *
+ * @param {ArrayBuffer} buffer - The buffer containing balance data.
+ * @returns {{ nonce: bigint, value: bigint }} The parsed balance data.
+ */
+const parseBalance = (buffer) => {
+  const view = new DataView(buffer);
+  const nonce = view.getBigUint64(0, true);
+  const value = view.getBigUint64(8, true);
+
+  return { nonce, value };
+};
+
+/**
+ * Syncs account data by querying the network for balance and stake information.
+ *
+ * @extends EventTarget
+ */
 export class AccountSyncer extends EventTarget {
+  /** @type {Object} */
   #network;
 
+  /**
+   * Creates an AccountSyncer instance.
+   * @param {Object} network - The network interface for accessing accounts.
+   */
   constructor(network) {
     super();
     this.#network = network;
   }
 
+  /**
+   * Fetches the balances for the given profiles.
+   *
+   * @param {Array<Object>} profiles - Array of profile objects.
+   * @returns {Promise<Array<{ nonce: bigint, value: bigint }>>} Array of balances.
+   */
   async balances(profiles) {
-    const rawUsers = await ProtocolDriver.accountsIntoRaw(
-      profiles.map(intoAccount)
+    const balances = await accountsIntoRaw(profiles).then((rawUsers) =>
+      rawUsers.map((user) =>
+        this.#network.contracts.transferContract.call.account(user)
+      )
     );
 
-    let balances = rawUsers.map((user) =>
-      this.#network.contracts.transferContract.call.account(user)
+    return Promise.all(balances)
+      .then((responses) => responses.map((resp) => resp.arrayBuffer()))
+      .then((buffers) => Promise.all(buffers))
+      .then((buffers) => buffers.map(parseBalance));
+  }
+
+  /**
+   * Fetches the stakes for the given profiles.
+   *
+   * @param {Array<Object>} profiles - Array of profile objects.
+   * @returns {Promise<Array<StakeInfo>>} Array of parsed stake information.
+   */
+  async stakes(profiles) {
+    const stakes = await accountsIntoRaw(profiles).then((rawUsers) =>
+      rawUsers.map((user) =>
+        this.#network.contracts.stakeContract.call.get_stake(user)
+      )
     );
 
-    return await Promise.all(balances)
+    return Promise.all(stakes)
       .then((responses) => responses.map((resp) => resp.arrayBuffer()))
       .then((buffers) => Promise.all(buffers))
-      .then((buffers) =>
-        buffers.map((buffer) => ({
-          nonce: new DataView(buffer).getBigUint64(0, true),
-          value: new DataView(buffer).getBigUint64(8, true),
-        }))
-      );
+      .then((buffers) => buffers.map(StakeInfo.parse));
   }
 }
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/profile.js b/web-wallet/src/lib/vendor/w3sper.js/src/profile.js
index 4d0cc8b6ac..ada3a4750f 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/profile.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/profile.js
@@ -6,7 +6,7 @@
 // Copyright (c) DUSK NETWORK. All rights reserved.
 
 import * as ProtocolDriver from "../src/protocol-driver/mod.js";
-import * as base58 from "./b58.js";
+import * as base58 from "./encoders/b58.js";
 
 const _index = Symbol("profile::index");
 const _seeder = Symbol("profile::seeder");
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 6bd242209f..a3ead4b0e9 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
@@ -574,6 +574,15 @@ export const moonlight = async (info) =>
     let tx = await malloc(4);
     let hash = await malloc(64);
 
+    const data = serializeMemo(info.data);
+
+    if (data) {
+      ptr.data = await malloc(data.byteLength);
+      await memcpy(ptr.data, data);
+    } else {
+      ptr.data = null;
+    }
+
     // Copy the value to the WASM memory
     const code = await moonlight(
       ptr.seed,
@@ -585,7 +594,7 @@ export const moonlight = async (info) =>
       ptr.gas_price,
       ptr.nonce,
       info.chainId,
-      info.data,
+      ptr.data,
       tx,
       hash
     );
@@ -783,3 +792,28 @@ export const shield = async (info) =>
     hash = new TextDecoder().decode(await memcpy(null, hash, 64));
     return [tx_buffer, hash];
   })();
+
+function serializeMemo(memo) {
+  if (!memo) {
+    return null;
+  }
+
+  let buffer = null;
+  if (typeof memo === "string") {
+    buffer = new TextEncoder().encode(memo);
+  } else if (memo instanceof ArrayBuffer) {
+    buffer = new Uint8Array(memo);
+  } else if (memo instanceof Uint8Array) {
+    buffer = memo;
+  }
+
+  if (!buffer) {
+    return null;
+  }
+
+  const memoBuffer = new Uint8Array(1 + buffer.byteLength);
+  memoBuffer[0] = 3; // Memo type
+  memoBuffer.set(buffer, 1);
+
+  return new Uint8Array(DataBuffer.from(memoBuffer));
+}
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/rues/event.js b/web-wallet/src/lib/vendor/w3sper.js/src/rues/event.js
index c09cba2575..8c545b4dbc 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/rues/event.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/rues/event.js
@@ -53,16 +53,19 @@ export class RuesEvent extends Event {
   }
 
   static from(event, options = {}) {
+    let headers;
+    let payload;
+
     if (event instanceof MessageEvent) {
       const { data } = event;
       const headersLength = new DataView(data).getUint32(0, true);
       const headersBuffer = new Uint8Array(data, 4, headersLength);
-      const headers = new Headers(
+
+      headers = new Headers(
         JSON.parse(new TextDecoder().decode(headersBuffer))
       );
       const body = new Uint8Array(data, 4 + headersLength);
 
-      let payload;
       switch (headers.get("content-type")) {
         case "application/json":
           payload = JSON.parse(new TextDecoder().decode(body));
@@ -77,28 +80,20 @@ export class RuesEvent extends Event {
             payload = body;
           }
       }
-
-      let type = new RuesEventOrigin(
-        headers.get("content-location"),
-        options
-      ).toString();
-
-      const ruesEvent = new RuesEvent(type);
-      ruesEvent.#headers = headers;
-      ruesEvent.#payload = payload;
-
-      return ruesEvent;
     } else if (event instanceof RuesEvent) {
-      let type = new RuesEventOrigin(
-        event.headers.get("content-location"),
-        options
-      ).toString();
+      headers = event.headers;
+      payload = event.payload;
+    }
 
-      const ruesEvent = new RuesEvent(type);
-      ruesEvent.#headers = event.headers;
-      ruesEvent.#payload = event.payload;
+    let type = new RuesEventOrigin(
+      headers.get("content-location"),
+      options
+    ).toString();
 
-      return ruesEvent;
-    }
+    const ruesEvent = new this(type);
+    ruesEvent.#headers = headers;
+    ruesEvent.#payload = payload;
+
+    return ruesEvent;
   }
 }
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/rues/mod.js b/web-wallet/src/lib/vendor/w3sper.js/src/rues/mod.js
index 17e8a3c620..1c4ed4857d 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/rues/mod.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/rues/mod.js
@@ -8,6 +8,7 @@
 import { CallableProxy } from "./callable.js";
 import { ListenerProxy } from "./listener.js";
 import { RuesEvent } from "./event.js";
+import { RuesScope } from "./scope.js";
 
 const _rues = Symbol("rues");
 
@@ -64,12 +65,15 @@ class RuesTarget {
 export class Rues extends EventTarget {
   #url;
   #socket;
+  #scopes;
   #session;
   #version = "0.8.0";
 
   constructor(url, options = {}) {
     super();
 
+    this.#scopes = new Map();
+
     if (typeof url === "string") {
       this.#url = new URL(url);
     } else if (!(url instanceof URL)) {
@@ -155,7 +159,16 @@ export class Rues extends EventTarget {
     return this.#socket?.readyState === WebSocket.OPEN;
   }
 
-  scope(name, options = {}) {
+  scope(source, options = {}) {
+    let name;
+
+    if (typeof source === "string") {
+      name = source;
+    } else if (source instanceof RuesScope) {
+      ({ name } = source);
+      this.#scopes.set(name, source);
+    }
+
     const target = new RuesTarget(name, options);
     target[_rues] = this;
 
@@ -165,6 +178,13 @@ export class Rues extends EventTarget {
   handleEvent(event) {
     if (event instanceof MessageEvent) {
       let ruesEvent = RuesEvent.from(event);
+
+      const scope = this.#scopes.get(ruesEvent.origin.scope);
+
+      if (scope) {
+        ruesEvent = scope.eventFrom(ruesEvent);
+      }
+
       let ruesComponentEvent = RuesEvent.from(ruesEvent, { as: "component" });
 
       this.dispatchEvent(ruesEvent);
diff --git a/web-wallet/src/lib/vendor/w3sper.js/src/rues/scope.js b/web-wallet/src/lib/vendor/w3sper.js/src/rues/scope.js
new file mode 100644
index 0000000000..18c8e59b74
--- /dev/null
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/rues/scope.js
@@ -0,0 +1,16 @@
+// @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.
+
+export class RuesScope {
+  constructor(name) {
+    this.name = name;
+  }
+
+  eventFrom(ruesEvent) {
+    return ruesEvent;
+  }
+}
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 ea8ab956bc..d75bc7ffe1 100644
--- a/web-wallet/src/lib/vendor/w3sper.js/src/transaction.js
+++ b/web-wallet/src/lib/vendor/w3sper.js/src/transaction.js
@@ -9,10 +9,10 @@ export const TRANSFER =
   "0100000000000000000000000000000000000000000000000000000000000000";
 
 import { AddressSyncer } from "./network/syncer/address.js";
-import { Gas } from "./network/gas.js";
 import * as ProtocolDriver from "./protocol-driver/mod.js";
 import { ProfileGenerator, Profile } from "./profile.js";
-import * as base58 from "./b58.js";
+import * as base58 from "./encoders/b58.js";
+import { Gas } from "./gas.js";
 
 const _attributes = Symbol("builder::attributes");
 
@@ -86,10 +86,15 @@ class AccountTransfer extends Transfer {
     return this;
   }
 
+  memo(value) {
+    this[_attributes].memo = value;
+    return this;
+  }
+
   async build(network) {
     const sender = this.bookentry.profile;
     const { attributes } = this;
-    const { to, amount: transfer_value, gas } = attributes;
+    const { to, amount: transfer_value, memo: data, gas } = attributes;
 
     const receiver = base58.decode(to);
 
@@ -122,7 +127,7 @@ class AccountTransfer extends Transfer {
       gas_price: gas.price,
       nonce,
       chainId,
-      data: null,
+      data,
     });
 
     return Object.freeze({
diff --git a/web-wallet/src/lib/vendor/wallet_core.wasm b/web-wallet/src/lib/vendor/wallet_core.wasm
index 0d1fbd1c44..e98a5cfe2c 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/__tests__/index.spec.js b/web-wallet/src/lib/wallet-cache/__tests__/index.spec.js
index 58369c3516..f779a2e0b9 100644
--- a/web-wallet/src/lib/wallet-cache/__tests__/index.spec.js
+++ b/web-wallet/src/lib/wallet-cache/__tests__/index.spec.js
@@ -15,12 +15,14 @@ import {
   take,
   takeFrom,
   uniques,
+  updatePathIn,
 } from "lamb";
 
 import {
   cacheBalances,
   cachePendingNotesInfo,
   cacheSpentNotes,
+  cacheStakeInfo,
   cacheSyncInfo,
   cacheUnspentNotes,
 } from "$lib/mock-data";
@@ -181,6 +183,26 @@ describe("Wallet cache", () => {
       ).resolves.toStrictEqual([]);
     });
 
+    it("should expose a method to retrieve the cached stake info for a given account", async () => {
+      for (const stakeInfo of cacheStakeInfo) {
+        await expect(
+          walletCache.getStakeInfo(stakeInfo.account)
+        ).resolves.toStrictEqual(stakeInfo.stakeInfo);
+      }
+    });
+
+    it('should return "empty" stake info if none is stored in the cache for the given account', async () => {
+      await expect(
+        walletCache.getStakeInfo("fake-account")
+      ).resolves.toStrictEqual({
+        amount: null,
+        faults: 0,
+        hardFaults: 0,
+        nonce: 0n,
+        reward: 0n,
+      });
+    });
+
     it("should expose a method to retrieve the sync info, which returns `{ blockHeight: 0n, bookmark: 0n }` if there is no info stored", async () => {
       await expect(walletCache.getSyncInfo()).resolves.toStrictEqual(
         cacheSyncInfo[0]
@@ -577,14 +599,21 @@ describe("Wallet cache", () => {
         ).resolves.toStrictEqual(balanceInfo.balance);
       }
 
+      // overwrite test
+      const modifiedBalance = updatePathIn(
+        newBalance.balance,
+        "shielded.value",
+        add(345n)
+      );
+
       await walletCache.setBalanceInfo(
         cacheBalances[0].address,
-        newBalance.balance
+        modifiedBalance
       );
 
       await expect(
         walletCache.getBalanceInfo(cacheBalances[0].address)
-      ).resolves.toStrictEqual(newBalance.balance);
+      ).resolves.toStrictEqual(modifiedBalance);
     });
 
     it("should expose a method to update the last block height", async () => {
@@ -647,6 +676,53 @@ describe("Wallet cache", () => {
       ).resolves.toStrictEqual(expectedInfo);
     });
 
+    it("should expose a method to set the stake info of a given account", async () => {
+      const newStakeInfo = {
+        account: "fake-account",
+        stakeInfo: {
+          amount: {
+            eligibility: 123n,
+            locked: 789n,
+            get total() {
+              return this.value + this.locked;
+            },
+            value: 3456n,
+          },
+          faults: 1,
+          hardFaults: 1,
+          nonce: 10n,
+          reward: 9000n,
+        },
+      };
+
+      await walletCache.setStakeInfo(
+        newStakeInfo.account,
+        newStakeInfo.stakeInfo
+      );
+
+      for (const stakeInfo of cacheStakeInfo.concat(newStakeInfo)) {
+        await expect(
+          walletCache.getStakeInfo(stakeInfo.account)
+        ).resolves.toStrictEqual(stakeInfo.stakeInfo);
+      }
+
+      // overwrite test
+      const modifiedStakeInfo = updatePathIn(
+        newStakeInfo.stakeInfo,
+        "amount.eligibility",
+        add(345n)
+      );
+
+      await walletCache.setStakeInfo(
+        cacheStakeInfo[0].account,
+        modifiedStakeInfo
+      );
+
+      await expect(
+        walletCache.getStakeInfo(cacheStakeInfo[0].account)
+      ).resolves.toStrictEqual(modifiedStakeInfo);
+    });
+
     it("should expose a method to convert notes in the w3sper map format into the one used by the cache", () => {
       const addresses = uniques(pluckFrom(cacheUnspentNotes, "address"));
       const fakeProfiles = addresses.map((address) => ({
diff --git a/web-wallet/src/lib/wallet-cache/index.js b/web-wallet/src/lib/wallet-cache/index.js
index 3767c123c3..5ffa2eee8f 100644
--- a/web-wallet/src/lib/wallet-cache/index.js
+++ b/web-wallet/src/lib/wallet-cache/index.js
@@ -1,6 +1,7 @@
 import { Dexie } from "dexie";
 import {
   compose,
+  condition,
   getKey,
   getPath,
   head,
@@ -15,8 +16,8 @@ import {
   when,
 } from "lamb";
 
-/** @typedef {{ nullifiers?: Uint8Array[] } | { addresses?: string[] }} RawCriteria */
-/** @typedef {{ field: "nullifier", values: Uint8Array[] } | { field: "address", values: string[]} | undefined} Criteria */
+/** @typedef {{ nullifiers?: Uint8Array[] } | { addresses?: string[] } | { accounts?: string[] }} RawCriteria */
+/** @typedef {{ field: "nullifier", values: Uint8Array[] } | { field: "address", values: string[]} | { field: "account", values: string[]} | undefined} Criteria */
 
 /** @type {(buffer: ArrayBuffer) => Uint8Array} */
 const bufferToUint8Array = (buffer) => new Uint8Array(buffer);
@@ -45,7 +46,12 @@ const toCriteria = pipe([
   pairs,
   head,
   unless(isUndefined, (pair) => ({
-    field: pair[0] === "nullifiers" ? "nullifier" : "address",
+    field:
+      pair[0] === "nullifiers"
+        ? "nullifier"
+        : pair[0] === "addresses"
+          ? "address"
+          : "account",
     values: pair[1],
   })),
 ]);
@@ -93,6 +99,15 @@ class WalletCache {
       unspentNotes: "nullifier,address",
     });
 
+    db.version(2).stores({
+      balancesInfo: "address",
+      pendingNotesInfo: "nullifier,txId",
+      spentNotes: "nullifier,address",
+      stakeInfo: "account",
+      syncInfo: "++",
+      unspentNotes: "nullifier,address",
+    });
+
     this.#db = db;
   }
 
@@ -167,6 +182,43 @@ class WalletCache {
     );
   }
 
+  /**
+   * @param {string} account
+   * @returns {Promise<StakeInfo>}
+   */
+  getStakeInfo(account) {
+    return this.#getEntriesFrom("stakeInfo", false, {
+      accounts: [account],
+    })
+      .then(getPath("0.stakeInfo"))
+      .then(
+        condition(
+          isUndefined,
+          () => ({
+            amount: null,
+            faults: 0,
+            hardFaults: 0,
+            nonce: 0n,
+            reward: 0n,
+          }),
+
+          // we reinstate the `total` getter if the
+          // amount is not `null`
+          (stakeInfo) => ({
+            ...stakeInfo,
+            amount: stakeInfo.amount
+              ? {
+                  ...stakeInfo.amount,
+                  get total() {
+                    return this.value + this.locked;
+                  },
+                }
+              : null,
+          })
+        )
+      );
+  }
+
   /** @returns {Promise<WalletCacheSyncInfo>} */
   getSyncInfo() {
     return this.#getEntriesFrom("syncInfo", false)
@@ -272,6 +324,20 @@ class WalletCache {
       .finally(() => this.#db.close());
   }
 
+  /**
+   * @param {string} account
+   * @param {StakeInfo} stakeInfo
+   * @returns {Promise<void>}
+   */
+  async setStakeInfo(account, stakeInfo) {
+    return this.#db
+      .open()
+      .then(async (db) => {
+        await db.table("stakeInfo").put({ account, stakeInfo });
+      })
+      .finally(() => this.#db.close());
+  }
+
   /**
    * @param {Uint8Array[]} nullifiers
    * @returns {Promise<void>}
diff --git a/web-wallet/src/lib/wallet-cache/wallet-cache.d.ts b/web-wallet/src/lib/wallet-cache/wallet-cache.d.ts
index 15a83cb6c0..2225570585 100644
--- a/web-wallet/src/lib/wallet-cache/wallet-cache.d.ts
+++ b/web-wallet/src/lib/wallet-cache/wallet-cache.d.ts
@@ -17,14 +17,23 @@ type WalletCacheDbNote = Omit<WalletCacheNote, "note" | "nullifier"> & {
   nullifier: ArrayBuffer;
 };
 
+type WalletCacheDbStakeInfo = {
+  account: string;
+  stakeInfo: Omit<StakeInfo, "amount"> & {
+    amount: null | Omit<Exclude<StakeAmount, null>, "total">;
+  };
+};
+
 type WalletCacheGetDataType<T extends WalletCacheTableName> =
   T extends "balancesInfo"
     ? WalletCacheBalanceInfo[]
     : T extends "pendingNotesInfo"
       ? WalletCacheDbPendingNoteInfo[]
-      : T extends "syncInfo"
-        ? WalletCacheSyncInfo[]
-        : WalletCacheDbNote[];
+      : T extends "stakeInfo"
+        ? WalletCacheDbStakeInfo[]
+        : T extends "syncInfo"
+          ? WalletCacheSyncInfo[]
+          : WalletCacheDbNote[];
 
 type WalletCacheGetEntriesReturnType<
   T extends WalletCacheTableName,
@@ -35,7 +44,9 @@ type WalletCacheGetEntriesReturnType<
     ? never
     : T extends "balancesInfo"
       ? never
-      : ArrayBuffer[];
+      : T extends "stakeInfo"
+        ? never
+        : ArrayBuffer[];
 
 type WalletCacheHistoryEntry = {
   history: Transaction[];
@@ -67,4 +78,5 @@ type WalletCacheTableName =
   | "pendingNotesInfo"
   | "syncInfo"
   | "spentNotes"
+  | "stakeInfo"
   | "unspentNotes";
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 eb4bed189e..a2be7eb3ef 100644
--- a/web-wallet/src/lib/wallet-treasury/__tests__/index.spec.js
+++ b/web-wallet/src/lib/wallet-treasury/__tests__/index.spec.js
@@ -128,5 +128,38 @@ describe("WalletTreasury", () => {
       ).toStrictEqual(sortNullifiers(pluckFrom(expectedNotes, "note")));
       expect(unspentNotesMapB).toStrictEqual(new Map());
     });
+
+    it("should implement the `stakeInfo` method of the treasury interface to retrieve the stake info for a given account", async () => {
+      const abortController = new AbortController();
+
+      await walletTreasury.update(0n, () => {}, abortController.signal);
+
+      // @ts-expect-error We don't care to pass a real `Key` object right now
+      await expect(walletTreasury.stakeInfo(fakeKey)).resolves.toStrictEqual(
+        expect.objectContaining({
+          amount: expect.objectContaining({
+            eligibility: expect.any(BigInt),
+            locked: expect.any(BigInt),
+            total: expect.any(BigInt),
+            value: expect.any(BigInt),
+          }),
+          faults: expect.any(Number),
+          hardFaults: expect.any(Number),
+          nonce: expect.any(BigInt),
+          reward: expect.any(BigInt),
+        })
+      );
+    });
+
+    it("should return a rejected promise if the `stakeInfo` method isn't able to find the stake info for the given account", async () => {
+      await expect(
+        // @ts-expect-error We don't care to pass a real `Key` object right now
+        walletTreasury.stakeInfo({
+          toString() {
+            return "non-existent address";
+          },
+        })
+      ).rejects.toThrow();
+    });
   });
 });
diff --git a/web-wallet/src/lib/wallet-treasury/index.js b/web-wallet/src/lib/wallet-treasury/index.js
index 6487b9525f..55a4702745 100644
--- a/web-wallet/src/lib/wallet-treasury/index.js
+++ b/web-wallet/src/lib/wallet-treasury/index.js
@@ -10,6 +10,9 @@ class WalletTreasury {
 
   #profiles;
 
+  /** @type {StakeInfo[]} */
+  #accountStakeInfo = [];
+
   /** @param {Array<import("$lib/vendor/w3sper.js/src/mod").Profile>} profiles */
   constructor(profiles = []) {
     this.#profiles = profiles;
@@ -59,6 +62,23 @@ class WalletTreasury {
     this.#profiles = profiles;
   }
 
+  /**
+   * @param {import("$lib/vendor/w3sper.js/src/mod").Profile["account"]} identifier
+   * @returns {Promise<StakeInfo>}
+   */
+  async stakeInfo(identifier) {
+    const stakeInfo = this.#accountStakeInfo.at(+identifier);
+
+    return (
+      stakeInfo ??
+      Promise.reject(
+        new Error(
+          "No stake info found for the account with the given identifier"
+        )
+      )
+    );
+  }
+
   /**
    * @param {bigint | import("$lib/vendor/w3sper.js/src/mod").Bookmark} from
    * @param {(evt: CustomEvent) => void} syncIterationListener
@@ -72,7 +92,10 @@ class WalletTreasury {
     // @ts-ignore
     addressSyncer.addEventListener("synciteration", syncIterationListener);
 
-    this.#accountBalances = await accountSyncer.balances(this.#profiles);
+    [this.#accountBalances, this.#accountStakeInfo] = await Promise.all([
+      accountSyncer.balances(this.#profiles),
+      accountSyncer.stakes(this.#profiles),
+    ]);
 
     const notesStream = await addressSyncer.notes(this.#profiles, {
       from,
diff --git a/web-wallet/src/lib/wallet-treasury/wallet-treasury.d.ts b/web-wallet/src/lib/wallet-treasury/wallet-treasury.d.ts
index 75be1673ec..bb78cfcd11 100644
--- a/web-wallet/src/lib/wallet-treasury/wallet-treasury.d.ts
+++ b/web-wallet/src/lib/wallet-treasury/wallet-treasury.d.ts
@@ -7,3 +7,9 @@ type AddressBalance = {
   spendable: bigint;
   value: bigint;
 };
+
+type StakeInfo = Awaited<
+  ReturnType<import("$lib/vendor/w3sper.js/src/mod").AccountSyncer["stakes"]>
+>[number];
+
+type StakeAmount = StakeInfo["amount"];
diff --git a/web-wallet/src/lib/wallet/wallet.d.ts b/web-wallet/src/lib/wallet/wallet.d.ts
index 5be373d72d..bcc2a847cf 100644
--- a/web-wallet/src/lib/wallet/wallet.d.ts
+++ b/web-wallet/src/lib/wallet/wallet.d.ts
@@ -3,10 +3,3 @@ type MnemonicEncryptInfo = {
   iv: Uint8Array;
   salt: Uint8Array;
 };
-
-type WalletStakeInfo = {
-  amount: number;
-  reward: number;
-  has_key: boolean;
-  has_staked: boolean;
-};
diff --git a/web-wallet/src/routes/(app)/dashboard/staking/__tests__/__snapshots__/page.spec.js.snap b/web-wallet/src/routes/(app)/dashboard/staking/__tests__/__snapshots__/page.spec.js.snap
index 0bf71360b1..7c9d03ea80 100644
--- a/web-wallet/src/routes/(app)/dashboard/staking/__tests__/__snapshots__/page.spec.js.snap
+++ b/web-wallet/src/routes/(app)/dashboard/staking/__tests__/__snapshots__/page.spec.js.snap
@@ -89,7 +89,7 @@ exports[`Staking > should render the staking page 1`] = `
             class="contract-statuses__value svelte-1up3579"
           >
             <span>
-              0.000000000
+              N/A
             </span>
              
             <svg
@@ -145,7 +145,6 @@ exports[`Staking > should render the staking page 1`] = `
         >
           <button
             class="dusk-button dusk-button--type--button dusk-button--variant--primary dusk-button--size--default dusk-icon-button--labeled contract-operations__operation-button"
-            disabled=""
             type="button"
           >
             <svg