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

Issue:
web-wallet: Improve Migration Functionality
#### Description
The current Migration functionality in the Web Wallet requires improvements to align with best practices, enhance user experience, and ensure consistency across components. This issue outlines several tasks to achieve these goals.

#### Tasks
1. **Remove `metadata`:**
   - `metadata` is currently used for analytics purposes, but analytics have been disabled.

2. **Add ENV Variable for Reown Project ID:**
   - Replace the hardcoded Reown Project ID with an environment variable for improved configurability and security.

3. **Add Labels to the Stepper:**
   - Include the following labels to the `Stepper` component for better clarity:
     - "Approve"
     - "Migrate"
     - "Done"

4. **Align Migrate Flow Layout:**
   - The current Migrate flow uses a custom layout instead of the standardized `Wizard` used in other flows. Update the layout to ensure a consistent look and feel across all flows.

5. **Update Approval Success Copy:**
   - Replace the existing approval success message ("Migration Approved") with a less confusing message. Suggested copy:  
     - **"Approval successful! You may now proceed with the migration."**

6. **Remove `migrationInProgress` Flag:**
   - The `migrationInProgress` flag is currently not being used and should be removed to clean up the codebase. Follow up: https://github.com/dusk-network/rusk/issues/3135

7. **Replace Migration Requirements Details with the `Banner` Component:**
   - Use the `Banner` component to display migration requirements, ensuring a consistent and visually appealing presentation.

8. **Add Notices for Each Step:**
   - Add additional notices to make it clear to the user what is happening at each step. This is especially important at the end, once the Migration is on-chain and our backend is processing the request, as this might take time.

9. **Retrigger Sync Post-Migration:**
   - Automatically retrigger a sync after a successful migration (likely after 10-15 seconds) to ensure that users see their funds immediately reflected in the wallet.


#### Expected Outcome
- The Migration functionality is more user-friendly and consistent with other parts of the application.
- Codebase is simplified by removing unnecessary `metadata`, unused flags, and hardcoded values.
- Users are provided with clearer guidance and improved overall experience during the migration process.
- Migration requirements are displayed in a standardized format using the `Banner` component.
- Users are better informed at every step of the process, reducing potential confusion or concern.
- Successful migrations result in prompt fund visibility within the wallet.

#### Additional Context
These changes are intended to streamline the Migration process and ensure the UI adheres to design and UX standards.



Discussion / hints:

Fix patch:
diff --git a/web-wallet/CHANGELOG.md b/web-wallet/CHANGELOG.md
index 9e83e3fb71..29d8cc2545 100644
--- a/web-wallet/CHANGELOG.md
+++ b/web-wallet/CHANGELOG.md
@@ -9,10 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
+- Add "VITE_REOWN_PROJECT_ID" ENV variable [#3267]
+- Add additional notices to the Migrate flow [#3267]
+
 ### Changed
 
 - Update Transactions list design [#1922]
 - Prioritize Public Account in the interface and transaction flows [#3259]
+- Enhance Migrate flow layout, aligning it to the rest of the transaction-based flows [#3267]
+- Display the Migration Requirements details using the `Banner` component [#3267]
+- Update the Approval Success copy for clarity (Migrate flow) [#3267]
+- Trigger sync after a successful migration [#3267]
 - Disable source wallet option on migration initialization (Migrate flow) [#3270]
 
 ### Removed
@@ -481,6 +488,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 [#3245]: https://github.com/dusk-network/rusk/issues/3245
 [#3259]: https://github.com/dusk-network/rusk/issues/3259
 [#3265]: https://github.com/dusk-network/rusk/issues/3265
+[#3267]: https://github.com/dusk-network/rusk/issues/3267
 [#3270]: https://github.com/dusk-network/rusk/issues/3270
 
 <!-- VERSIONS -->
diff --git a/web-wallet/README.md b/web-wallet/README.md
index 9311813137..8619b0c401 100644
--- a/web-wallet/README.md
+++ b/web-wallet/README.md
@@ -44,6 +44,7 @@ VITE_GAS_LIMIT_UPPER=1000000000
 VITE_GAS_PRICE_DEFAULT=1
 VITE_GAS_PRICE_LOWER=1
 VITE_MODE_MAINTENANCE=false
+VITE_REOWN_PROJECT_ID="" # the ID of the Bridge project (as on Reown Cloud)
 VITE_NODE_URL="" # connect to a specific node
 ```
 
diff --git a/web-wallet/src/lib/components/ApproveMigration/ApproveMigration.svelte b/web-wallet/src/lib/components/ApproveMigration/ApproveMigration.svelte
index 6938e8533c..acf1daed99 100644
--- a/web-wallet/src/lib/components/ApproveMigration/ApproveMigration.svelte
+++ b/web-wallet/src/lib/components/ApproveMigration/ApproveMigration.svelte
@@ -6,6 +6,7 @@
   import { isHex } from "viem";
   import { createEventDispatcher } from "svelte";
   import { Button, Icon } from "$lib/dusk/components";
+  import { Banner } from "$lib/components";
   import { account, wagmiConfig } from "$lib/migration/walletConnection";
   import { allowance, approve } from "$lib/migration/migration";
   import { createDataStore } from "$lib/dusk/svelte-stores";
@@ -85,27 +86,37 @@
 
 <div class="migrate__approve">
   {#if !isLoading && !error && !data}
-    <div class="migrate__approve-notice">
-      <p>DUSK token migration requires two transactions:</p>
-      <ol class="migrate__approve-notice-list">
-        <li>
-          Approve: Authorize the migration contract to spend your DUSK tokens.
-        </li>
-        <li>Migrate: Transfer your DUSK tokens to the migration contract.</li>
-      </ol>
-      <p>
-        Both steps must be completed for a successful migration.<br /><br
-        />Warning: Make sure your wallet has enough funds to pay for the gas.
-      </p>
+    <div class="migrate__approve-notice-container">
+      <Banner title="Migration Requirements" variant="info">
+        <div class="migrate__requirements-info">
+          <p>DUSK token migration requires two transactions:</p>
+          <ol class="migrate__requirements-info-list">
+            <li>
+              <b>Approve:</b> Authorize the migration contract to spend your DUSK
+              tokens.
+            </li>
+            <li>
+              <b>Migrate:</b> Transfer your DUSK tokens to the migration contract.
+            </li>
+          </ol>
+          <p>Both steps must be completed for a successful migration.</p>
+        </div>
+      </Banner>
+      <Banner title="Gas Fee Reminder" variant="warning">
+        <p>
+          Please ensure your wallet has sufficient funds to cover the gas fees
+          for the migration.
+        </p>
+      </Banner>
     </div>
   {:else if isLoading}
     <div class="migrate__approve-approval">
-      <Icon path={mdiTimerSand} />
+      <Icon path={mdiTimerSand} size="large" />
       <span>Approval in progress...</span>
     </div>
   {:else if error}
     <div class="migrate__approve-approval">
-      <Icon path={mdiAlertOutline} />
+      <Icon path={mdiAlertOutline} size="large" />
       <span>An error occurred during approval</span>
     </div>
   {/if}
@@ -118,23 +129,27 @@
 </div>
 
 <style lang="postcss">
+  .migrate {
+    &__requirements-info {
+      display: flex;
+      flex-direction: column;
+      gap: var(--small-gap);
+    }
+    &__requirements-info-list {
+      list-style-position: inside;
+    }
+  }
+
   .migrate__approve {
     display: flex;
     justify-content: center;
     flex-direction: column;
+    gap: 1.875em;
 
-    &-notice {
-      font-size: 0.875em;
-      line-height: 1.3125em;
-      padding: 1em 1.375em;
-      border-radius: 0.675em;
-      border: 1px solid var(--primary-color);
-      margin-top: 0.625em;
-      margin-bottom: 1em;
-
-      &-list {
-        padding-left: 1.375em;
-      }
+    &-notice-container {
+      display: flex;
+      flex-direction: column;
+      gap: var(--default-gap);
     }
 
     &-approval {
@@ -142,7 +157,6 @@
       flex-direction: column;
       align-items: center;
       gap: var(--default-gap);
-      padding: 2.25em 0;
     }
   }
 </style>
diff --git a/web-wallet/src/lib/components/ExecuteMigration/ExecuteMigration.svelte b/web-wallet/src/lib/components/ExecuteMigration/ExecuteMigration.svelte
index dbf5a12492..12b870e86b 100644
--- a/web-wallet/src/lib/components/ExecuteMigration/ExecuteMigration.svelte
+++ b/web-wallet/src/lib/components/ExecuteMigration/ExecuteMigration.svelte
@@ -14,6 +14,7 @@
   import { migrate } from "$lib/migration/migration";
   import { createDataStore } from "$lib/dusk/svelte-stores";
   import { createEventDispatcher } from "svelte";
+  import { walletStore } from "$lib/stores";
 
   /** @type {bigint} */
   export let amount;
@@ -46,6 +47,9 @@
       });
       if (result.status === "success") {
         dispatch("incrementStep");
+        setTimeout(() => {
+          walletStore.sync();
+        }, 20000);
       } else {
         throw new Error("Could not validate the transaction receipt");
       }
@@ -58,35 +62,35 @@
 <div class="migrate__execute">
   {#if !isLoading && !data && !error}
     <div class="migrate__execute-approval">
-      <Icon path={mdiCheckDecagramOutline} />
-      <span>Migration Approved</span>
+      <Icon path={mdiCheckDecagramOutline} size="large" />
+      <span>Approval successful! You may now proceed with the migration.</span>
     </div>
   {:else if error}
     <div class="migrate__execute-approval">
-      <Icon path={mdiAlertOutline} />
+      <Icon path={mdiAlertOutline} size="large" />
       <span>Action has been rejected on the connected wallet.</span>
     </div>
   {:else if isLoading && !migrationHash}
     <div class="migrate__execute-approval">
-      <Icon path={mdiTimerSand} />
+      <Icon path={mdiTimerSand} size="large" />
       <span>Migration in progress...</span>
     </div>
   {/if}
   {#if migrationHash && chain?.blockExplorers}
     <div class="migrate__execute-approval">
-      <Icon path={mdiTimerSand} />
-      <span>Migration has been submitted</span>
+      <Icon path={mdiTimerSand} size="large" />
+      <span>Your migration request is being processed...</span>
+      <Banner title="Migration in Progress" variant="info">
+        <p>
+          Your migration request is currently being executed and may take a few
+          minutes to complete. You can track the transaction status <AppAnchor
+            href={`${chain.blockExplorers.default.url}/tx/${migrationHash}`}
+            target="_blank"
+            rel="noopener noreferrer">here</AppAnchor
+          >.
+        </p>
+      </Banner>
     </div>
-    <Banner title="Migration in progress..." variant="info">
-      <p>
-        Migration takes some minutes to complete. Your transaction is being
-        executed and you can check its status <AppAnchor
-          href={`${chain.blockExplorers.default.url}/tx/${migrationHash}`}
-          target="_blank"
-          rel="noopener noreferrer">here</AppAnchor
-        >.
-      </p>
-    </Banner>
   {/if}
   {#if (isLoading || !data || error) && !migrationHash}
     <Button
@@ -102,13 +106,13 @@
     display: flex;
     justify-content: center;
     flex-direction: column;
+    gap: 1.875em;
 
     &-approval {
       display: flex;
       flex-direction: column;
       align-items: center;
       gap: var(--default-gap);
-      padding: 2.25em 0;
     }
   }
 </style>
diff --git a/web-wallet/src/lib/containers/MigrateContract/MigrateContract.svelte b/web-wallet/src/lib/containers/MigrateContract/MigrateContract.svelte
index e6fadacf2d..dec67f2b96 100644
--- a/web-wallet/src/lib/containers/MigrateContract/MigrateContract.svelte
+++ b/web-wallet/src/lib/containers/MigrateContract/MigrateContract.svelte
@@ -18,7 +18,6 @@
     middleEllipsis,
   } from "$lib/dusk/string";
   import {
-    AppAnchor,
     AppAnchorButton,
     AppImage,
     ApproveMigration,
@@ -27,7 +26,6 @@
   } from "$lib/components";
   import {
     Button,
-    Card,
     ExclusiveChoice,
     Icon,
     Stepper,
@@ -74,9 +72,6 @@
   /** @type {TokenNames} */
   let selectedChain = erc20.name;
 
-  /** @type {boolean} */
-  const migrationInProgress = false;
-
   /** @type {undefined | bigint} */
   let connectedWalletBalance;
 
@@ -95,6 +90,8 @@
   /** @type {boolean} */
   let isInputDisabled = false;
 
+  const steps = [{ label: "Approve" }, { label: "Migrate" }, { label: "Done" }];
+
   $: ({ currentProfile } = $walletStore);
   $: moonlightAccount = currentProfile?.account.toString();
 
@@ -244,16 +241,6 @@
     </div>
   </header>
 
-  {#if migrationInProgress}
-    <div class="migrate__progress-notice">
-      <span
-        >Another migration is in progress. You can check the status <AppAnchor
-          href="#">here</AppAnchor
-        >.</span
-      >
-    </div>
-  {/if}
-
   <div class="migrate__token">
     <p class="migrate__token-header">From:</p>
     <ExclusiveChoice
@@ -332,8 +319,8 @@
   {/if}
 
   {#if walletState.isConnected && isAmountValid && isMigrationInitialized}
-    <Card gap="small">
-      <Stepper steps={3} activeStep={migrationStep} />
+    <div class="migrate__wizard">
+      <Stepper {steps} activeStep={migrationStep} />
       {#if migrationStep === 0}
         <ApproveMigration
           on:incrementStep={() => migrationStep++}
@@ -356,11 +343,20 @@
         />
       {:else}
         <div class="migrate__execute">
-          <Icon path={mdiCheckDecagramOutline} />
-          <p>Migration completed successfully!</p>
+          <div class="migrate__execute-approval">
+            <Icon path={mdiCheckDecagramOutline} size="large" />
+            <p>Migration request accepted!</p>
+          </div>
+          <Banner title="Migration Request Accepted" variant="info">
+            <p>
+              The migration request has now been accepted on chain. We will
+              process the request in the background. Receiving your DUSK might
+              take some time. Check your wallet balance again later.
+            </p>
+          </Banner>
         </div>
       {/if}
-    </Card>
+    </div>
   {/if}
 
   {#if !walletState.isConnected}
@@ -410,12 +406,25 @@
     gap: var(--default-gap);
     padding: 1.25em;
 
+    &__wizard {
+      margin-top: var(--default-gap);
+      gap: 1.25em;
+      display: flex;
+      flex-direction: column;
+    }
+
     &__execute {
       display: flex;
       flex-direction: column;
       align-items: center;
       gap: var(--default-gap);
-      padding: 2.25em 0;
+
+      &-approval {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        gap: var(--default-gap);
+      }
     }
 
     &__header {
@@ -445,12 +454,6 @@
       align-items: center;
     }
 
-    &__progress-notice {
-      padding: 1em 1.375em;
-      border-radius: 1.5em;
-      border: 1px solid var(--primary-color);
-    }
-
     &__token-header {
       font-weight: 500;
     }
diff --git a/web-wallet/src/lib/contracts/contract-descriptors.js b/web-wallet/src/lib/contracts/contract-descriptors.js
index fc1eca8a13..3cf391d91e 100644
--- a/web-wallet/src/lib/contracts/contract-descriptors.js
+++ b/web-wallet/src/lib/contracts/contract-descriptors.js
@@ -57,7 +57,9 @@ export default [
     ],
   },
   {
-    enabled: import.meta.env.VITE_FEATURE_MIGRATE === "true",
+    enabled:
+      import.meta.env.VITE_FEATURE_MIGRATE === "true" &&
+      import.meta.env.VITE_REOWN_PROJECT_ID !== "",
     id: "migrate",
     label: "Migrate",
     operations: [
diff --git a/web-wallet/src/lib/migration/walletConnection.js b/web-wallet/src/lib/migration/walletConnection.js
index 8eeae93979..de61b7b27a 100644
--- a/web-wallet/src/lib/migration/walletConnection.js
+++ b/web-wallet/src/lib/migration/walletConnection.js
@@ -5,14 +5,25 @@ import { bsc, mainnet, sepolia } from "@reown/appkit/networks";
 import { disconnect, getAccount, getBalance, watchAccount } from "@wagmi/core";
 import { readable } from "svelte/store";
 
-// Required project metadata
-const projectId = "b5303e1c8374b100fbb7f181884fef28";
-const metadata = {
-  description: "Dusk Web-Wallet",
-  icons: [],
-  name: "Dusk Migration",
-  url: "https://127.0.0.1:5173/dashboard/",
-};
+/**
+ * @constant {string} projectId - The ID of the project, sourced from an environment variable.
+ *
+ * @description
+ * This constant retrieves the project ID from the environment variable `VITE_REOWN_PROJECT_ID`.
+ * If the environment variable is not set, it defaults to an empty string. This behavior is not ideal
+ * because an empty `projectId` will cause the modal initialization to fail.
+ *
+ * While this issue typically arises due to a developer error (e.g., forgetting to set the environment variable),
+ * resolving it properly requires a broader refactor of the codebase to better handle missing or invalid `projectId` values.
+ *
+ * Additionally, when the `projectId` is missing, the "migrate" functionality will not be accessible in the UI,
+ * effectively hiding the "broken" flow. Therefore, while the error can occur, users are unlikely to encounter it.
+ *
+ * **To improve:**
+ * Consider implementing a mechanism to ensure `VITE_REOWN_PROJECT_ID` is always defined during the build or
+ * runtime processes, potentially throwing a clear error during startup if it is missing.
+ */
+const projectId = import.meta.env.VITE_REOWN_PROJECT_ID || "";
 
 /** @typedef {import("@reown/appkit/networks").AppKitNetwork} AppKitNetwork */
 /** @type {[AppKitNetwork, ...AppKitNetwork[]]} */
@@ -33,7 +44,6 @@ export const modal = createAppKit({
     onramp: false,
     swaps: false,
   },
-  metadata,
   networks,
   projectId,
   themeMode: "dark",
diff --git a/web-wallet/vite.config.js b/web-wallet/vite.config.js
index 6057f59419..f7e515fdfb 100644
--- a/web-wallet/vite.config.js
+++ b/web-wallet/vite.config.js
@@ -50,6 +50,7 @@ export default defineConfig(({ mode }) => {
         VITE_GAS_PRICE_LOWER: env.VITE_GAS_PRICE_LOWER,
         VITE_GAS_PRICE_UPPER: env.VITE_GAS_PRICE_UPPER,
         VITE_NODE_URL: env.VITE_NODE_URL,
+        VITE_REOWN_PROJECT_ID: env.VITE_REOWN_PROJECT_ID,
       },
     },
     plugins:


Test patch: