diff --git a/.env.example b/.env.example
index 02da18d30921de2977463f0fa9b65c48d0e3ef1d..7fb22e942afe52ac9617dca322a3b05d2adf9f98 100644
--- a/.env.example
+++ b/.env.example
@@ -1,2 +1,4 @@
-# To use this, rename to `.env` and set the production SNAP_ORIGIN here
-SNAP_ORIGIN=
+## To use this, rename to `.env` and set the production VITE_SNAP_ORIGIN here
+VITE_SNAP_ORIGIN=
+## Uncomment this if you want to use a specific version of the Snap runtime:
+# VITE_SNAP_VERSION=
diff --git a/LICENSE.md b/LICENSE.md
index fee679976df85d66e7d7d6f6db021e8fb9f42b61..ec43082c9c9794ba0c1cb53df89a8852c857ed1f 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,16 +1,7 @@
-MIT No Attribution
+Copyright (c) 2024 Hive community
 
-Copyright 2024 Hive Community
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of this
-software and associated documentation files (the "Software"), to deal in the Software
-without restriction, including without limitation the rights to use, copy, modify,
-merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so.
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/package.json b/package.json
index cc7fe506c8464d2235ec26bfa3779b8bcb0dd9d5..9cc4a816090ea5e000629a1175e0f2125011442f 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,9 @@
     "build": "vue-tsc -b && vite build",
     "preview": "vite preview"
   },
-  "dependencies": {},
+  "dependencies": {
+    "vue-sonner": "^1.3.0"
+  },
   "devDependencies": {
     "@hiveio/wax": "1.27.6-rc7-250304235913",
     "@mdi/js": "^7.4.47",
@@ -38,13 +40,13 @@
     "pinia": "^3.0.1",
     "reka-ui": "^2.0.2",
     "tailwind-merge": "^3.0.2",
-    "tailwindcss-animate": "^1.0.7",
     "tailwindcss": "3",
+    "tailwindcss-animate": "^1.0.7",
     "typescript": "~5.7.2",
     "vite": "^6.2.0",
-    "vue-tsc": "^2.2.4",
     "vue": "^3.5.13",
-    "vue-router": "4"
+    "vue-router": "4",
+    "vue-tsc": "^2.2.4"
   },
   "packageManager": "pnpm@10.0.0+sha512.b8fef5494bd3fe4cbd4edabd0745df2ee5be3e4b0b8b08fa643aa3e4c6702ccc0f00d68fa8a8c9858a735a0032485a44990ed2810526c875e416f001b17df12b",
   "engines": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2e8ca622634e4aff39a2a11937af46e654d1033b..4bdf1ab30e51784388b397e575e9f34072b0b2a1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -7,6 +7,10 @@ settings:
 importers:
 
   .:
+    dependencies:
+      vue-sonner:
+        specifier: ^1.3.0
+        version: 1.3.0
     devDependencies:
       '@hiveio/wax':
         specifier: 1.27.6-rc7-250304235913
@@ -1448,6 +1452,9 @@ packages:
     peerDependencies:
       vue: ^3.2.0
 
+  vue-sonner@1.3.0:
+    resolution: {integrity: sha512-jAodBy4Mri8rQjVZGQAPs4ZYymc1ywPiwfa81qU0fFl+Suk7U8NaOxIDdI1oBGLeQJqRZi/oxNIuhCLqsBmOwg==}
+
   vue-tsc@2.2.8:
     resolution: {integrity: sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ==}
     hasBin: true
@@ -2796,6 +2803,8 @@ snapshots:
       '@vue/devtools-api': 6.6.4
       vue: 3.5.13(typescript@5.7.3)
 
+  vue-sonner@1.3.0: {}
+
   vue-tsc@2.2.8(typescript@5.7.3):
     dependencies:
       '@volar/typescript': 2.4.11
diff --git a/src/App.vue b/src/App.vue
index 50cbd6ffc730c677af222bc2a22581907d6330df..39b0508f8d5e01cb0ca15ec95e869a7410766200 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -5,6 +5,7 @@ import { useWalletStore } from '@/stores/wallet.store';
 import AppSidebar from '@/components/sidebar';
 import { SidebarProvider } from '@/components/ui/sidebar';
 import ToggleSidebar from './components/sidebar/ToggleSidebar.vue';
+import { Toaster } from 'vue-sonner';
 
 const WalletOnboarding = defineAsyncComponent(() => import('@/components/onboarding/index'));
 
@@ -42,6 +43,7 @@ const complete = (data: { account: string; wallet: UsedWallet }) => {
           <WalletOnboarding @complete="complete" />
         </aside>
       </SidebarProvider>
+      <Toaster theme="dark" closeButton richColors />
     </div>
   </div>
 </template>
diff --git a/src/components/ui/textarea/Textarea.vue b/src/components/ui/textarea/Textarea.vue
index 329bb59255b3567a54011352f35731addb667fdd..2fdc0b830d50ee5fc4f1f460150f834c2aaa1942 100644
--- a/src/components/ui/textarea/Textarea.vue
+++ b/src/components/ui/textarea/Textarea.vue
@@ -27,6 +27,6 @@ const modelValue = useVModel(props, 'modelValue', emits, {
 <template>
   <div :class="cn(props.class, 'relative')">
     <textarea :disabled="disabled" :placeholder="placeholder" :style="{ height: props.height ?? '100px' }" v-model="modelValue" :class="'flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50'" />
-    <Button class="absolute top-[10px] right-[10px]" :value="modelValue" v-if="copyEnabled" />
+    <Button class="absolute top-[10px] right-[10px]" :value="modelValue" v-if="(modelValue || modelValue === 0) && copyEnabled" />
   </div>
 </template>
diff --git a/src/components/utilcards/MemoEncryptCard.vue b/src/components/utilcards/MemoEncryptCard.vue
index 7694c8256d4c71ea1c36d1173ff7227325316a36..f0bdaf9a4465f445c6c18f46596119603de32bf8 100644
--- a/src/components/utilcards/MemoEncryptCard.vue
+++ b/src/components/utilcards/MemoEncryptCard.vue
@@ -9,6 +9,7 @@ import { Switch } from '@/components/ui/switch';
 import { useWalletStore } from '@/stores/wallet.store';
 import { getWax } from '@/stores/wax.store';
 import { useSettingsStore } from '@/stores/settings.store';
+import { toastError } from '@/lib/parse-error';
 
 const walletStore = useWalletStore();
 const settingsStore = useSettingsStore();
@@ -21,31 +22,44 @@ const encryptForKey = ref('');
 const inputData = ref('');
 const outputData = ref('');
 
-const getMemoKeyForUser = async(user: string) => {
-  const wax = await getWax();
-  const response = await wax.api.database_api.find_accounts({
-    accounts: [user.startsWith('@') ? user.slice(1) : user],
-    delayed_votes_active: true
-  });
-  return response.accounts[0].memo_key;
+const getMemoKeyForUser = async(user: string): Promise<string | void> => {
+  const accountName = user.startsWith('@') ? user.slice(1) : user;
+  try {
+    const wax = await getWax();
+    const response = await wax.api.database_api.find_accounts({
+      accounts: [accountName],
+      delayed_votes_active: true
+    });
+    return response.accounts[0].memo_key;
+  } catch (error) {
+    toastError(`Error retrieving memo key for account: @${accountName}`, error);
+  }
 }
 
 const useMyMemoKey = async () => {
-  encryptForKey.value = await getMemoKeyForUser(settingsStore.account!);
+  const key = await getMemoKeyForUser(settingsStore.account!);
+  if (key)
+    encryptForKey.value = key;
 }
 
 const encryptOrDecrypt = async () => {
-  if (isEncrypt.value) {
-    let publicKey: string;
-    let accountOrKey = encryptForKey.value;
-    if (accountOrKey.startsWith('STM')) {
-      publicKey = accountOrKey;
+  try {
+    if (isEncrypt.value) {
+      let publicKey: string;
+      let accountOrKey = encryptForKey.value;
+      if (accountOrKey.startsWith('STM')) {
+        publicKey = accountOrKey;
+      } else {
+        const key = await getMemoKeyForUser(accountOrKey);
+        if (!key) return;
+        publicKey = key;
+      }
+      outputData.value = await wallet.value!.encrypt(inputData.value, publicKey);
     } else {
-      publicKey = await getMemoKeyForUser(accountOrKey);
+      outputData.value = await wallet.value!.decrypt(inputData.value);
     }
-    outputData.value = await wallet.value!.encrypt(inputData.value, publicKey);
-  } else {
-    outputData.value = await wallet.value!.decrypt(inputData.value);
+  } catch (error) {
+    toastError(`Error ${isEncrypt.value ? 'encrypting' : 'decrypting'} memo`, error);
   }
 };
 </script>
diff --git a/src/components/utilcards/SignTransactionCard.vue b/src/components/utilcards/SignTransactionCard.vue
index 8f8f2aeef4dcad6b27104559e28235ae905a37c9..f1c500fe9d589b717a0395f65202e1a5fc519d5e 100644
--- a/src/components/utilcards/SignTransactionCard.vue
+++ b/src/components/utilcards/SignTransactionCard.vue
@@ -6,8 +6,9 @@ import { Textarea } from '@/components/ui/textarea';
 import { Button } from '@/components/ui/button';
 import { useWalletStore } from '@/stores/wallet.store';
 import { getWax } from '@/stores/wax.store';
-import type { TRole } from '@hiveio/wax/vite';
+import type { ITransactionBase, TRole } from '@hiveio/wax/vite';
 import { useRouter } from 'vue-router';
+import { toastError } from '@/lib/parse-error';
 
 const walletStore = useWalletStore();
 
@@ -19,30 +20,62 @@ const outputData = ref('');
 
 const router = useRouter();
 
+const isLoading = ref(false);
+
 const sign = async () => {
-  const wax = await getWax();
+  try {
+    isLoading.value = true;
+
+    try {
+      JSON.parse(inputData.value);
+    } catch (error) {
+      toastError('Could not process the transaction object', error);
+      return;
+    }
+
+    const wax = await getWax();
 
-  const tx = wax.createTransactionFromJson(inputData.value);
+    let tx: ITransactionBase;
 
-  const authorities = tx.requiredAuthorities;
-  let authorityLevel: TRole = 'posting';
-  if (authorities.owner.size)
-    authorityLevel = 'owner';
-  else if (authorities.active.size)
-    authorityLevel = 'active';
+    try {
+      tx = wax.createTransactionFromJson(inputData.value);
+    } catch (error) {
+      toastError('Could not process the transaction object', error);
+      return;
+    }
 
-  // TODO: Handle "other" authority
+      const authorities = tx.requiredAuthorities;
+      let authorityLevel: TRole = 'posting';
+      if (authorities.owner.size)
+        authorityLevel = 'owner';
+      else if (authorities.active.size)
+        authorityLevel = 'active';
 
-  outputData.value = await wallet.value!.signTransaction(tx, authorityLevel);
+    // TODO: Handle "other" authority
+
+    outputData.value = await wallet.value!.signTransaction(tx, authorityLevel);
+  } catch (error) {
+    toastError('Error signing transaction', error);
+  } finally {
+    isLoading.value = false;
+  }
 };
 
 const broadcast = async () => {
-  const wax = await getWax();
+  try {
+    isLoading.value = true;
+
+    const wax = await getWax();
 
-  const tx = wax.createTransactionFromJson(inputData.value);
-  tx.sign(outputData.value);
+    const tx = wax.createTransactionFromJson(inputData.value);
+    tx.sign(outputData.value);
 
-  wax.broadcast(tx);
+    wax.broadcast(tx);
+  } catch (error) {
+    toastError('Error broadcasting transaction', error);
+  } finally {
+    isLoading.value = false;
+  }
 };
 
 onMounted(() => {
@@ -62,11 +95,11 @@ onMounted(() => {
     <CardContent>
       <Textarea v-model="inputData" placeholder="Transaction in API JSON form" class="my-4"/>
       <div class="my-4 space-x-4">
-        <Button :disabled="!hasWallet" @click="sign">Sign transaction</Button>
+        <Button :disabled="!inputData || !hasWallet || isLoading" @click="sign">Sign transaction</Button>
       </div>
       <Textarea v-model="outputData" placeholder="Signature" copy-enabled class="my-4" disabled/>
       <div class="my-4 space-x-4">
-        <Button :disabled="!outputData" @click="broadcast">Broadcast signed transaction</Button>
+        <Button :disabled="!outputData || isLoading" @click="broadcast">Broadcast signed transaction</Button>
       </div>
     </CardContent>
   </Card>
diff --git a/src/lib/parse-error.ts b/src/lib/parse-error.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dcc327320e5e058d506aa283d973bd2c00ce81a0
--- /dev/null
+++ b/src/lib/parse-error.ts
@@ -0,0 +1,27 @@
+import { WaxChainApiError, WaxError } from "@hiveio/wax/vite";
+import { toast } from "vue-sonner";
+
+export const toastError = (title: string, error: unknown) => {
+  let description: string;
+
+  if (typeof error === "object" && error) {
+    if (error instanceof WaxError) {
+      if (error instanceof WaxChainApiError) {
+        if (error.apiError && typeof error.apiError === "object" && "message" in error.apiError && typeof error.apiError.message === "string")
+          description = error.apiError.message;
+        else
+          description = error.message;
+      } else {
+        description = error.message;
+      }
+    } else if ("message" in Error) {
+      description = (error as Error).message;
+    } else {
+      description = String(error);
+    }
+  } else {
+    description = String(error);
+  }
+
+  toast.error(title, { description });
+};
diff --git a/src/utils/wallet/metamask/snap.ts b/src/utils/wallet/metamask/snap.ts
index ffb7a9b84c7b00c6fcee463952b0e74e4f6a24da..a7ac0399aae529b7f2c75cdacf31682bc9af46bc 100644
--- a/src/utils/wallet/metamask/snap.ts
+++ b/src/utils/wallet/metamask/snap.ts
@@ -6,9 +6,9 @@
  * don't. Instead, rename `.env.production.dist` to `.env.production` and set the production URL
  * there. Running `yarn build` will automatically use the production environment variables.
  */
-export const defaultSnapOrigin = import.meta.env.SNAP_ORIGIN ?? `npm:@hiveio/metamask-snap`; // local:http://localhost:8080
+export const defaultSnapOrigin = import.meta.env.VITE_SNAP_ORIGIN || `npm:@hiveio/metamask-snap`; // local:http://localhost:8080
 
-export const defaultSnapVersion: string | undefined = import.meta.env.SNAP_VERSION ?? '1.2.1';
+export const defaultSnapVersion: string | undefined = import.meta.env.VITE_SNAP_VERSION ?? '1.3.2';
 
 /**
  * Check if a snap ID is a local snap ID.