diff --git a/Client/Account.cs b/Client/Account.cs
index 892d9b9..7fe02b4 100644
--- a/Client/Account.cs
+++ b/Client/Account.cs
@@ -9,7 +9,6 @@ namespace Client
     public class Account
     {
         public decimal balance;
-        string owner;
         public List<Transaction> History { get; }
         public Account(decimal balance)
         {
diff --git a/Client/BankNetInteractor.cs b/Client/BankNetInteractor.cs
index a8ce72d..6849bb3 100644
--- a/Client/BankNetInteractor.cs
+++ b/Client/BankNetInteractor.cs
@@ -196,6 +196,14 @@ namespace Client
             });
         }
 
+        public async virtual Task<Promise> ListUsers()
+        {
+            await StatusCheck(true);
+            client.Send(CreateCommandMessage("List", sessionID, out var pID));
+            RefreshTimeout();
+            return RegisterPromise(pID);
+        }
+
         public async virtual Task<Promise> CreateAccount(string accountName)
         {
             await StatusCheck(true);
diff --git a/Client/ConsoleForms/ConsoleController.cs b/Client/ConsoleForms/ConsoleController.cs
index 1455054..3fe2a8c 100644
--- a/Client/ConsoleForms/ConsoleController.cs
+++ b/Client/ConsoleForms/ConsoleController.cs
@@ -90,19 +90,27 @@ namespace Client.ConsoleForms
             for (int i = renderQueue.Count - 1; i >= 0; --i)
                 if (renderQueue[i].Item1.Equals(v))
                 {
+                    // Compute occlusion region
                     Region test = renderQueue[i].Item1.Occlusion;
                     test.Offset(renderQueue[i].Item2.ComputeLayoutParams(width, height));
                     Region removing = test.Subtract(r);
                     needsRedraw |= removing.Area > 0;
 
+                    // Check whether or not view is completely occluded: if it is not, a redraw is required, else redraw isn't necessary
                     Region cmp;
                     for (int j = i - 1; !needsRedraw && j >= 0; --j)
                         needsRedraw |= (cmp = renderQueue[j].Item1.Occlusion).Subtract(removing).Area != cmp.Area;
 
+                    // Trigger close event (immediately before closing)
+                    v.OnClose?.Invoke(v);
+
+                    // Remove view from renderqueue and clear it from the screen
                     renderQueue.RemoveAt(i);
                     ClearRegion(removing);
                     if (++closed == maxCloses) break;
                 }
+
+            // Redraw if necessary
             if (redraw && needsRedraw) Draw(false);
         }
 
@@ -147,7 +155,7 @@ namespace Client.ConsoleForms
             int lowestDirty = renderQueue.Count;
             int count = renderQueue.Count - 1;
             for (int i = count; i >= 0; --i)
-                if (renderQueue[i].Item1.HandleKeyEvent(keyInfo, i == count))
+                if (renderQueue[i].Item1.HandleKeyEvent(keyInfo, i == count, false))
                     lowestDirty = i;
             if (redrawOnDirty) Draw(false, lowestDirty);
             return keyInfo;
diff --git a/Client/ConsoleForms/Graphics/ButtonView.cs b/Client/ConsoleForms/Graphics/ButtonView.cs
index 823c61a..90ff5ac 100644
--- a/Client/ConsoleForms/Graphics/ButtonView.cs
+++ b/Client/ConsoleForms/Graphics/ButtonView.cs
@@ -16,10 +16,10 @@ namespace Client.ConsoleForms.Graphics
         {
         }
 
-        public override bool HandleKeyEvent(ConsoleController.KeyEvent info, bool inFocus)
+        public override bool HandleKeyEvent(ConsoleController.KeyEvent info, bool inFocus, bool triggered)
         {
-            bool b = inFocus && info.ValidEvent && info.Event.Key == ConsoleKey.Enter;
-            base.HandleKeyEvent(info, inFocus);
+            bool b = (triggered || (inFocus && info.ValidEvent)) && info.Event.Key == ConsoleKey.Enter;
+            base.HandleKeyEvent(info, inFocus, triggered);
             if (b) evt?.Invoke(this);
             return b;
         }
diff --git a/Client/ConsoleForms/Graphics/DialogView.cs b/Client/ConsoleForms/Graphics/DialogView.cs
index 0020505..def0736 100644
--- a/Client/ConsoleForms/Graphics/DialogView.cs
+++ b/Client/ConsoleForms/Graphics/DialogView.cs
@@ -81,11 +81,11 @@ namespace Client.ConsoleForms.Graphics
             Console.Write(Filler(' ', pad - lpad));
         }
 
-        public override bool HandleKeyEvent(ConsoleController.KeyEvent evt, bool inFocus)
+        public override bool HandleKeyEvent(ConsoleController.KeyEvent evt, bool inFocus, bool triggered)
         {
-            bool changed = base.HandleKeyEvent(evt, inFocus);
+            bool changed = base.HandleKeyEvent(evt, inFocus, triggered);
             ConsoleKeyInfo info = evt.Event;
-            if (!evt.ValidEvent || !inFocus) return changed;
+            if (!triggered && (!evt.ValidEvent || !inFocus)) return changed;
             evt.ValidEvent = false; // Invalidate event
             switch (info.Key)
             {
diff --git a/Client/ConsoleForms/Graphics/InputView.cs b/Client/ConsoleForms/Graphics/InputView.cs
index fd68237..8df317f 100644
--- a/Client/ConsoleForms/Graphics/InputView.cs
+++ b/Client/ConsoleForms/Graphics/InputView.cs
@@ -12,7 +12,7 @@ namespace Client.ConsoleForms.Graphics
     public class InputView : TextView
     {
         public delegate void SubmissionListener(InputView view);
-        public delegate bool TextEnteredListener(InputView view, InputField change, ConsoleKeyInfo info);
+        public delegate bool TextEnteredListener(InputView view, InputField change, ConsoleKeyInfo info, bool triggered);
 
         public SubmissionListener SubmissionsListener { protected get; set; }
         public TextEnteredListener InputListener { protected get; set; }
@@ -53,7 +53,7 @@ namespace Client.ConsoleForms.Graphics
                 else fields.Add(new InputField(data.InnerText, data.AttribueAsInt("max_length", -1))
                 {
                     ShowText = !data.AttribueAsBool("hide", false),
-                    Text = data.GetAttribute("default"),
+                    Text = lang.MapIfExists(data.GetAttribute("default")),
                     InputTypeString = data.GetAttribute("input_type"),
                     TextColor = (ConsoleColor)data.AttribueAsInt("color_text", TC),
                     BackgroundColor = (ConsoleColor)data.AttribueAsInt("color_background", BC),
@@ -73,6 +73,14 @@ namespace Client.ConsoleForms.Graphics
             ContentHeight += computedSize + Inputs.Length * 2;
         }
 
+        public int IndexOf(InputField field)
+        {
+            for (int i = 0; i < Inputs.Length; ++i)
+                if (field.Equals(Inputs[i]))
+                    return i;
+            return -1;
+        }
+
         protected override void _Draw(int left, ref int top)
         {
             DrawContent(left, ref top);
@@ -114,11 +122,11 @@ namespace Client.ConsoleForms.Graphics
             }
         }
 
-        public override bool HandleKeyEvent(ConsoleController.KeyEvent evt, bool inFocus)
+        public override bool HandleKeyEvent(ConsoleController.KeyEvent evt, bool inFocus, bool triggered)
         {
-            bool changed = base.HandleKeyEvent(evt, inFocus);
+            bool changed = base.HandleKeyEvent(evt, inFocus, triggered);
             ConsoleKeyInfo info = evt.Event;
-            if (!evt.ValidEvent || !inFocus || Inputs.Length == 0) return changed;
+            if ((!triggered && (!evt.ValidEvent || !inFocus)) || Inputs.Length == 0) return changed;
             evt.ValidEvent = false;
             switch (info.Key)
             {
@@ -148,7 +156,7 @@ namespace Client.ConsoleForms.Graphics
                 case ConsoleKey.Backspace:
                     if (Inputs[selectedField].SelectIndex > 0)
                     {
-                        if (InputListener?.Invoke(this, Inputs[selectedField], info) == false) break;
+                        if (InputListener?.Invoke(this, Inputs[selectedField], info, triggered) == false) break;
                         string text = Inputs[selectedField].Text;
                         Inputs[selectedField].Text = text.Substring(0, Inputs[selectedField].SelectIndex - 1);
                         if (Inputs[selectedField].SelectIndex < text.Length) Inputs[selectedField].Text += text.Substring(Inputs[selectedField].SelectIndex);
@@ -159,7 +167,7 @@ namespace Client.ConsoleForms.Graphics
                 case ConsoleKey.Delete:
                     if (Inputs[selectedField].SelectIndex < Inputs[selectedField].Text.Length)
                     {
-                        if (InputListener?.Invoke(this, Inputs[selectedField], info) == false) break;
+                        if (InputListener?.Invoke(this, Inputs[selectedField], info, triggered) == false) break;
                         string text = Inputs[selectedField].Text;
                         Inputs[selectedField].Text = text.Substring(0, Inputs[selectedField].SelectIndex);
                         if (Inputs[selectedField].SelectIndex + 1 < text.Length) Inputs[selectedField].Text += text.Substring(Inputs[selectedField].SelectIndex + 1);
@@ -174,7 +182,7 @@ namespace Client.ConsoleForms.Graphics
                 default:
                     if (info.KeyChar != 0 && info.KeyChar != '\b' && info.KeyChar != '\r' && (Inputs[selectedField].Text.Length < Inputs[selectedField].MaxLength || Inputs[selectedField].MaxLength < 0) && Inputs[selectedField].IsValidChar(info.KeyChar))
                     {
-                        if (InputListener?.Invoke(this, Inputs[selectedField], info) == false) break;
+                        if (InputListener?.Invoke(this, Inputs[selectedField], info, triggered) == false) break;
                         Inputs[selectedField].Text = Inputs[selectedField].Text.Substring(0, Inputs[selectedField].SelectIndex) + info.KeyChar + Inputs[selectedField].Text.Substring(Inputs[selectedField].SelectIndex);
                         if (++Inputs[selectedField].SelectIndex - Inputs[selectedField].RenderStart == maxWidth) ++Inputs[selectedField].RenderStart;
                     }
diff --git a/Client/ConsoleForms/Graphics/ListView.cs b/Client/ConsoleForms/Graphics/ListView.cs
index e31aeb6..c53ed10 100644
--- a/Client/ConsoleForms/Graphics/ListView.cs
+++ b/Client/ConsoleForms/Graphics/ListView.cs
@@ -71,7 +71,7 @@ namespace Client.ConsoleForms.Graphics
         {
             foreach (var data in innerViews)
                 if (data.Item1 != null && data.Item1.Equals(viewID))
-                    throw new SystemException("Cannot load view with same id"); // TODO: Replace with custom exception
+                    return;
             innerViews.Insert(Math.Min(insert, innerViews.Count), new Tuple<string, View>(viewID, v));
         }
 
@@ -101,7 +101,12 @@ namespace Client.ConsoleForms.Graphics
         {
             for(int i = innerViews.Count - 1; i>=0; --i)
                 if (p(innerViews[i]))
+                {
                     innerViews.RemoveAt(i);
+                    if (SelectedView >= innerViews.Count) SelectedView = Math.Max(0, innerViews.Count - 1);
+                }
+            ComputeSize();
+            if (SelectedView >= innerViews.Count) SelectedView = Math.Max(0, innerViews.Count - 1);
         }
 
         protected void ComputeSize()
@@ -165,11 +170,11 @@ namespace Client.ConsoleForms.Graphics
             Console.Write(Filler(' ', ContentWidth));
         }
 
-        public override bool HandleKeyEvent(ConsoleController.KeyEvent info, bool inFocus)
+        public override bool HandleKeyEvent(ConsoleController.KeyEvent info, bool inFocus, bool triggered)
         {
-            if (!inFocus || !info.ValidEvent) return false;
+            if (!triggered && (!inFocus || !info.ValidEvent)) return false;
 
-            bool changed = base.HandleKeyEvent(info, inFocus) || innerViews[SelectedView].Item2.HandleKeyEvent(info, inFocus);
+            bool changed = base.HandleKeyEvent(info, inFocus, triggered) || innerViews[SelectedView].Item2.HandleKeyEvent(info, inFocus, triggered);
             info.ValidEvent = false;
             // Handle navigation
             switch (info.Event.Key)
diff --git a/Client/ConsoleForms/Graphics/TextView.cs b/Client/ConsoleForms/Graphics/TextView.cs
index 8affbdb..726ec6c 100644
--- a/Client/ConsoleForms/Graphics/TextView.cs
+++ b/Client/ConsoleForms/Graphics/TextView.cs
@@ -10,11 +10,28 @@ namespace Client.ConsoleForms.Graphics
 {
     public class TextView : View
     {
-        protected readonly string[] text;
+        protected string[] text;
         protected string[] text_render;
         protected int maxWidth, maxHeight;
 
-        public string Text { get; }
+        private string _text;
+        public string Text
+        {
+            get => _text;
+            protected set
+            {
+                _text = value;
+                text = _text.Split(' ');
+
+                // Compute the layout of the text to be rendered
+                text_render = ComputeTextDimensions(this.text);
+                int actualWidth = 0;
+                foreach (var t in text_render) if (actualWidth < t.Length) actualWidth = t.Length;
+                ContentWidth = maxWidth;// + padding.Left() + padding.Right();
+                ContentHeight = text_render.Length;// + padding.Top() + padding.Bottom();
+                Dirty = true;
+            }
+        }
 
         public int MaxWidth
         {
@@ -52,10 +69,7 @@ namespace Client.ConsoleForms.Graphics
 
         public TextView(ViewData parameters, LangManager lang) : base(parameters, lang)
         {
-            //BorderColor = (ConsoleColor) parameters.AttribueAsInt("border", (int)ConsoleColor.Blue);
-
             Border = ' ';
-            this.text = (Text = parameters.NestedText("Text")).Split(' ');
             int widest = 0;
             foreach (var t in parameters.NestedText("Text").Split('\n'))
                 if (t.Length > widest)
@@ -63,12 +77,7 @@ namespace Client.ConsoleForms.Graphics
             this.maxWidth = parameters.AttribueAsInt("width") < 1 ? widest : parameters.AttribueAsInt("width");
             this.maxHeight = parameters.AttribueAsInt("height", -1);
 
-            // Compute the layout of the text to be rendered
-            text_render = ComputeTextDimensions(this.text);
-            int actualWidth = 0;
-            foreach (var t in text_render) if (actualWidth < t.Length) actualWidth = t.Length;
-            ContentWidth = maxWidth;// + padding.Left() + padding.Right();
-            ContentHeight = text_render.Length;// + padding.Top() + padding.Bottom();
+            this.text = (Text = parameters.NestedText("Text")).Split(' ');
         }
 
         protected virtual string[] ComputeTextDimensions(string[] text)
diff --git a/Client/ConsoleForms/Graphics/View.cs b/Client/ConsoleForms/Graphics/View.cs
index 8718949..7fe8ee5 100644
--- a/Client/ConsoleForms/Graphics/View.cs
+++ b/Client/ConsoleForms/Graphics/View.cs
@@ -32,6 +32,7 @@ namespace Client.ConsoleForms.Graphics
         public bool Dirty { get; set; }
         public LangManager I18n { get; private set; }
         public ViewEvent OnBackEvent { get; set; }
+        public ViewEvent OnClose { get; set; }
 
         public View(ViewData parameters, LangManager lang)
         {
@@ -114,9 +115,9 @@ namespace Client.ConsoleForms.Graphics
             left += padding.Left() / 2; // Increment left offset
         }
         protected abstract void _Draw(int left, ref int top);
-        public virtual bool HandleKeyEvent(ConsoleController.KeyEvent info, bool inFocus)
+        public virtual bool HandleKeyEvent(ConsoleController.KeyEvent info, bool inFocus, bool triggered)
         {
-            if ((back_data.Length != 0 || OnBackEvent!=null) && info.ValidEvent && inFocus && info.Event.Key == ConsoleKey.Escape)
+            if ((back_data.Length != 0 || OnBackEvent!=null) && (triggered || (info.ValidEvent && inFocus)) && info.Event.Key == ConsoleKey.Escape)
             {
                 info.ValidEvent = false;
                 if(back_data.Length!=0) ParseAction(back_data, true)();
@@ -124,6 +125,7 @@ namespace Client.ConsoleForms.Graphics
             }
             return false;
         }
+        public virtual void TriggerKeyEvent(ConsoleController.KeyEvent info) => HandleKeyEvent(info, true, true);
         protected void DrawTopPadding(int left, ref int top) => DrawPadding(left, ref top, padding.Top());
         protected void DrawBottomPadding(int left, ref int top) => DrawPadding(left, ref top, padding.Bottom());
         private void DrawPadding(int left, ref int top, int count)
diff --git a/Client/Context/SessionContext.cs b/Client/Context/SessionContext.cs
index 3ddbb32..5e4e3df 100644
--- a/Client/Context/SessionContext.cs
+++ b/Client/Context/SessionContext.cs
@@ -1,4 +1,5 @@
 using Client.ConsoleForms;
+using Client.ConsoleForms.Events;
 using Client.ConsoleForms.Graphics;
 using Client.ConsoleForms.Parameters;
 using Client.Properties;
@@ -20,10 +21,17 @@ namespace Client
         private bool scheduleDestroy;
         private Promise userDataGetter;
         private Promise accountsGetter;
+        private Promise remoteAccountsGetter;
+        private Promise remoteUserGetter;
         private List<string> accounts = null;
         private string username;
         private bool isAdministrator = false;
+        
+        // Stores personal accounts
         private readonly FixedQueue<Tuple<string, decimal>> accountDataCache = new FixedQueue<Tuple<string, decimal>>(64);
+
+        // Stores remote account data
+        private readonly FixedQueue<Tuple<string, string>> remoteUserCache = new FixedQueue<Tuple<string, string>>(8);
         private bool accountChange = false;
 
 
@@ -32,13 +40,66 @@ namespace Client
             this.interactor = interactor;
             scheduleDestroy = !interactor.IsLoggedIn;
 
-            RegisterAutoHide("account_create", "account_info", "password_update", "exit_prompt", "account_show");
+            RegisterAutoHide("account_create", "account_info", "password_update", "exit_prompt", "account_show", "transfer");
 
             GetView<DialogView>("Success").RegisterSelectListener((v, i, s) => HandleLogout());
 
             // Menu option setup
             ListView options = GetView<ListView>("menu_options");
-            options.GetView<ButtonView>("exit").SetEvent(v => HandleLogout());
+            options.GetView<ButtonView>("exit").SetEvent(v => Show("exit_prompt"));
+
+            void SubmitListener(View listener)
+            {
+                ButtonView view = listener as ButtonView;
+
+                void ShowAccountData(string name, decimal balance)
+                {
+                    // Build dialog view manually
+                    var show = new DialogView(
+                        new ViewData("DialogView")
+
+                        // Layout parameters
+                        .SetAttribute("padding_left", 2)
+                        .SetAttribute("padding_right", 2)
+                        .SetAttribute("padding_top", 1)
+                        .SetAttribute("padding_bottom", 1)
+                        .SetAttribute("border", (int)ConsoleColor.DarkGreen)
+
+                        // Option buttons
+                        .AddNested(new ViewData("Options").AddNestedSimple("Option", GetIntlString("GENERIC_dismiss")))
+
+                        // Message
+                        .AddNestedSimple("Text", GetIntlString("SE_info").Replace("$0", name).Replace("$1", balance.ToString())),
+
+                        // No translation (it's already handled)
+                        LangManager.NO_LANG);
+
+                    show.RegisterSelectListener((_, s, l) => Hide(show));
+                    Show(show);
+                }
+
+                // TODO: Show account info
+                var account = AccountLookup(view.Text);
+                if (account == null)
+                {
+                    // TODO: Get account data from server + cache data
+                    Show("data_fetch");
+                    Promise info_promise = Promise.AwaitPromise(interactor.AccountInfo(view.Text));
+                    info_promise.Subscribe = evt =>
+                    {
+                        Hide("data_fetch");
+                        if (evt.Value.StartsWith("ERROR") || !Account.TryParse(evt.Value, out var act))
+                            controller.Popup(GetIntlString("GENERIC_error"), 3000, ConsoleColor.Red);
+                        else
+                        {
+                            accountDataCache.Enqueue(new Tuple<string, decimal>(view.Text, act.balance)); // Cache result
+                            ShowAccountData(view.Text, act.balance);
+                        }
+
+                    };
+                }
+                else ShowAccountData(account.Item1, account.Item2);
+            }
 
             options.GetView<ButtonView>("view").SetEvent(v =>
             {
@@ -48,76 +109,8 @@ namespace Client
                 {
                     accountsGetter.Unsubscribe();
                     Hide("data_fetch");
-
-                    void SubmitListener(View listener)
-                    {
-                        ButtonView view = listener as ButtonView;
-
-                        void ShowAccountData(string name, decimal balance)
-                        {
-                            // Build dialog view manually
-                            var show = new DialogView(
-                                new ViewData("DialogView")
-
-                                // Layout parameters
-                                .SetAttribute("padding_left", 2)
-                                .SetAttribute("padding_right", 2)
-                                .SetAttribute("padding_top", 1)
-                                .SetAttribute("padding_bottom", 1)
-
-                                // Option buttons
-                                .AddNested(new ViewData("Options").AddNestedSimple("Option", GetIntlString("GENERIC_dismiss")))
-
-                                // Message
-                                .AddNestedSimple("Text", GetIntlString("SE_info").Replace("$0", name).Replace("$1", balance.ToString())),
-
-                                // No translation (it's already handled)
-                                LangManager.NO_LANG);
-
-                            show.RegisterSelectListener((_, s, l) => Hide(show));
-                            Show(show);
-                        }
-
-                        // TODO: Show account info
-                        var account = AccountLookup(view.Text);
-                        if (account == null)
-                        {
-                            // TODO: Get account data from server + cache data
-                            Show("data_fetch");
-                            Promise info_promise = Promise.AwaitPromise(interactor.AccountInfo(view.Text));
-                            info_promise.Subscribe = evt =>
-                            {
-                                Hide("data_fetch");
-                                if (evt.Value.StartsWith("ERROR") || !Account.TryParse(evt.Value, out var act))
-                                    controller.Popup(GetIntlString("GENERIC_error"), 3000, ConsoleColor.Red);
-                                else
-                                {
-                                    accountDataCache.Enqueue(new Tuple<string, decimal>(view.Text, act.balance)); // Cache result
-                                    ShowAccountData(view.Text, act.balance);
-                                }
-                                
-                            };
-                        }
-                        else ShowAccountData(account.Item1, account.Item2);
-                    }
-
-                    var list = GetView<ListView>("account_show");
-                    list.RemoveIf(t => !t.Item1.Equals("close"));
-                    var data = p.Value.Split('&');
-                    bool b = data.Length == 1 && data[0].Length == 0;
-                    Tuple<string, View>[] listData = new Tuple<string, View>[data.Length - (b?1:0)];
-                    if(!b)
-                        for(int i = 0; i<listData.Length; ++i)
-                        {
-                            ButtonView t = new ButtonView(new ViewData("ButtonView").AddNestedSimple("Text", data[i].FromBase64String()), LangManager.NO_LANG); // Don't do translations
-                            t.SetEvent(SubmitListener);
-                            listData[i] = new Tuple<string, View>(t.Text, t);
-                        }
-                    string dismiss = GetIntlString("GENERIC_dismiss");
-                    ButtonView exit = list.GetView<ButtonView>("close");
-                    exit.SetEvent(_ => Hide(list));
-                    list.AddViews(0, listData); // Insert generated buttons before predefined "close" button
-                    Show(list);
+                    
+                    Show(GenerateList(p.Value.Split('&').ForEach(Support.FromBase64String), SubmitListener));
                 };
             });
 
@@ -189,7 +182,7 @@ namespace Client
                     }
                 }
             };
-            input.InputListener = (v, c, i) =>
+            input.InputListener = (v, c, i, t) =>
             {
                 c.BackgroundColor = v.DefaultBackgroundColor;
                 c.SelectBackgroundColor = v.DefaultSelectBackgroundColor;
@@ -199,7 +192,7 @@ namespace Client
             options.GetView<ButtonView>("add").SetEvent(_ => Show(input));
 
             // Set up a listener to reset color scheme
-            GetView<InputView>("password_update").InputListener = (v, c, i) =>
+            GetView<InputView>("password_update").InputListener = (v, c, i, t) =>
             {
                 c.BackgroundColor = v.DefaultBackgroundColor;
                 c.SelectBackgroundColor = v.DefaultSelectBackgroundColor;
@@ -209,19 +202,139 @@ namespace Client
             // Update password
             options.GetView<ButtonView>("update").SetEvent(v => Show("password_update"));
 
-            options.OnBackEvent = v =>
+
+            string acc1 = null, acc2 = null, user = null;
+
+            options.GetView<ButtonView>("tx").SetEvent(v =>
             {
-                Show("exit_prompt");
+                var txView = GetView<InputView>("transfer");
+                txView.Inputs[0].Text = GetIntlString("SE_account_select");
+                txView.Inputs[1].Text = GetIntlString("SE_user_select");
+                txView.Inputs[2].Text = GetIntlString("SE_account_select");
+                Show(txView);
+            });
+
+            GetView<InputView>("transfer").SubmissionsListener = v =>
+            {
+                switch (v.SelectedField)
+                {
+                    case 0:
+                        if (accountChange) accountsGetter = Promise.AwaitPromise(interactor.ListUserAccounts());
+                        Show("data_fetch");
+                        accountsGetter.Subscribe = p =>
+                        {
+                            accountsGetter.Unsubscribe();
+                            Hide("data_fetch");
+
+                            Show(GenerateList(p.Value.Split('&').ForEach(Support.FromBase64String), sel => v.Inputs[0].Text = acc1 = (sel as ButtonView).Text, true));
+                        };
+                        break;
+                    case 1:
+                        Show("data_fetch");
+                        remoteUserGetter = Promise.AwaitPromise(interactor.ListUsers());
+                        remoteUserGetter.Subscribe = p =>
+                        {
+                            remoteUserGetter.Unsubscribe();
+                            Hide("data_fetch");
+
+                            Show(GenerateList(p.Value.Split('&').ForEach(Support.FromBase64String), sel => v.Inputs[1].Text = user = (sel as ButtonView).Text, true));
+                        };
+                        break;
+                    case 2:
+                        if (user == null)
+                            controller.Popup(GetIntlString("SE_user_noselect"), 2000, ConsoleColor.Red);
+                        else
+                        {
+                            Show("data_fetch");
+                            remoteAccountsGetter = Promise.AwaitPromise(interactor.ListAccounts(user));
+                            remoteAccountsGetter.Subscribe = p =>
+                            {
+                                remoteUserGetter.Unsubscribe();
+                                Hide("data_fetch");
+
+                                Show(GenerateList(p.Value.Split('&').ForEach(Support.FromBase64String), sel => v.Inputs[2].Text = acc2 = (sel as ButtonView).Text, true));
+                            };
+                        }
+                        break;
+                    case 3:
+                    case 4:
+                        Show("verify_stall");
+                        bool error = false;
+                        if (acc1==null)
+                        {
+                            controller.Popup(GetIntlString("SE_account_noselect"), 1500, ConsoleColor.Red);
+                            error = true;
+                            v.Inputs[0].BackgroundColor = ConsoleColor.Red;
+                            v.Inputs[0].SelectBackgroundColor = ConsoleColor.DarkRed;
+                        }
+                        if (acc2 == null)
+                        {
+                            if(!error) controller.Popup(GetIntlString("SE_account_noselect"), 1500, ConsoleColor.Red);
+                            error = true;
+                            v.Inputs[2].BackgroundColor = ConsoleColor.Red;
+                            v.Inputs[2].SelectBackgroundColor = ConsoleColor.DarkRed;
+                        }
+                        if(user == null)
+                        {
+                            if(!error) controller.Popup(GetIntlString("SE_account_nouser"), 1500, ConsoleColor.Red);
+                            error = true;
+                            v.Inputs[1].BackgroundColor = ConsoleColor.DarkRed;
+                            v.Inputs[1].SelectBackgroundColor = ConsoleColor.Red;
+                        }
+                        userDataGetter = Promise.AwaitPromise(interactor.UserInfo());
+                        userDataGetter.Subscribe = p =>
+                        {
+                            userDataGetter.Unsubscribe();
+                            var account = AccountLookup("SE_balance_toohigh");
+                            if (account == null) accountsGetter = Promise.AwaitPromise(interactor.AccountInfo(acc1));
+                            accountsGetter.Subscribe = result =>
+                            {
+                                accountsGetter.Unsubscribe();
+                                var resultData = p.Value.Split('&');
+                                Hide("verify_stall");
+                                decimal d;
+                                if (result.Value.StartsWith("ERROR") || !Account.TryParse(result.Value, out var act))
+                                    controller.Popup(GetIntlString("GENERIC_error"), 1500, ConsoleColor.Red);
+                                else if ((d = decimal.Parse(v.Inputs[3].Text)) > act.balance && (!bool.Parse(resultData[1]) || !acc1.Equals(acc2)))
+                                    controller.Popup(GetIntlString("SE_balance_toohigh").Replace("$0", act.balance.ToString()), 3000, ConsoleColor.Red);
+                                else
+                                {
+                                    Promise txPromise = Promise.AwaitPromise(interactor.CreateTransaction(acc1, user, acc2, d, v.Inputs[4].Text.Length == 0 ? null : v.Inputs[4].Text));
+                                    accountChange = true;
+                                    accountDataCache.Clear();
+                                    txPromise.Subscribe = txResult =>
+                                    {
+                                        if (txResult.Value.StartsWith("ERROR"))
+                                            controller.Popup(GetIntlString("GENERIC_error"), 1500, ConsoleColor.Red);
+                                        else controller.Popup(GetIntlString("SE_tx_success"), 2000, ConsoleColor.Green, () => Hide("transfer"));
+                                    };
+                                }
+                            };
+                        };
+                        break;
+                }
             };
 
+            GetView<InputView>("transfer").InputListener = (v, i, s, t) =>
+            {
+                if (t) return false; // Don't handle artificial events
+                i.BackgroundColor = v.DefaultBackgroundColor;
+                i.SelectBackgroundColor = v.DefaultSelectBackgroundColor;
+                if (v.IndexOf(i) < 3)
+                {
+                    // Trigger a keypress event for key [ENTER]
+                    v.TriggerKeyEvent(new ConsoleController.KeyEvent(new ConsoleKeyInfo('\n', ConsoleKey.Enter, false, false, false)));
+                    return false; // Don't update input
+                }
+                return true;
+            };
+
+            options.OnBackEvent = v => Show("exit_prompt");
+
             GetView<DialogView>("exit_prompt").RegisterSelectListener((v, i, s) =>
             {
                 if (i == 0) Hide("exit_prompt");
-                else
-                {
-                    interactor.Logout();
-                    controller.ShouldExit = true;
-                }
+                else HandleLogout();
             });
 
             if (!scheduleDestroy)
@@ -232,6 +345,31 @@ namespace Client
             }
         }
 
+        private ListView GenerateList(string[] data, SubmissionEvent onclick, bool exitOnSubmit = false)
+        {
+            var list = GetView<ListView>("account_show");
+            list.RemoveIf(t => !t.Item1.Equals("close"));
+            ButtonView exit = list.GetView<ButtonView>("close");
+            exit.SetEvent(_ => Hide(list));
+            if (data.Length == 1 && data[0].Length == 0) return list;
+            bool b = data.Length == 1 && data[0].Length == 0;
+            Tuple<string, View>[] listData = new Tuple<string, View>[data.Length - (b ? 1 : 0)];
+            if (!b)
+                for (int i = 0; i < listData.Length; ++i)
+                {
+                    ButtonView t = new ButtonView(new ViewData("ButtonView").AddNestedSimple("Text", data[i]), LangManager.NO_LANG); // Don't do translations
+                    t.SetEvent(v =>
+                    {
+                        onclick?.Invoke(v);
+                        if (exitOnSubmit) Hide(list);
+                    });
+                    listData[i] = new Tuple<string, View>(t.Text, t);
+                }
+            list.RemoveIf(t => !t.Item1.Equals("close"));
+            list.AddViews(0, listData); // Insert generated buttons before predefined "close" button
+            return list;
+        }
+
         private void RefreshAccountList()
         {
             accountsGetter = Promise.AwaitPromise(interactor.ListUserAccounts()); // Get accounts associated with this user
@@ -258,7 +396,9 @@ namespace Client
 
         private void HandleLogout(bool automatic = false)
         {
+#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
             interactor.Logout();
+#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
             controller.Popup(GetIntlString($"SE_{(automatic ? "auto" : "")}lo"), 2500, ConsoleColor.DarkMagenta, () => manager.LoadContext(new NetContext(manager)));
         }
 
diff --git a/Client/Context/WelcomeContext.cs b/Client/Context/WelcomeContext.cs
index 2d7035e..19656cf 100644
--- a/Client/Context/WelcomeContext.cs
+++ b/Client/Context/WelcomeContext.cs
@@ -71,7 +71,7 @@ namespace Client
             };
 
             // For a smooth effect
-            GetView<InputView>("Login").InputListener = (v, c, i) =>
+            GetView<InputView>("Login").InputListener = (v, c, i, t) =>
             {
                 c.BackgroundColor = v.DefaultBackgroundColor;
                 c.SelectBackgroundColor = v.DefaultSelectBackgroundColor;
@@ -138,7 +138,7 @@ namespace Client
                 else Show("EmptyFieldError");
             };
 
-            GetView<InputView>("Register").InputListener = (v, c, i) =>
+            GetView<InputView>("Register").InputListener = (v, c, i, t) =>
             {
                 c.BackgroundColor = v.DefaultBackgroundColor;
                 c.SelectBackgroundColor = v.DefaultSelectBackgroundColor;
diff --git a/Client/Resources/Layout/Common.xml b/Client/Resources/Layout/Common.xml
index a5369eb..181881c 100644
--- a/Client/Resources/Layout/Common.xml
+++ b/Client/Resources/Layout/Common.xml
@@ -30,4 +30,13 @@
     padding_bottom="1">
     <Text>@string/GENERIC_fetch</Text>
   </TextView>
+
+  <TextView id="verify_stall"
+    padding_left="2"
+    padding_right="2"
+    padding_top="1"
+    padding_bottom="1">
+    <Text>@string/SE_checking</Text>
+  </TextView>
+
 </Resources>
\ No newline at end of file
diff --git a/Client/Resources/Layout/Session.xml b/Client/Resources/Layout/Session.xml
index e98497b..aa84c34 100644
--- a/Client/Resources/Layout/Session.xml
+++ b/Client/Resources/Layout/Session.xml
@@ -42,6 +42,33 @@
     <Text>@string/SE_pwdu</Text>
   </InputView>
   
+  <InputView id="transfer"
+    padding_left="2"
+    padding_right="2"
+    padding_top="1"
+    padding_bottom="1">
+    <Fields>
+      <Field>@string/SE_where_f</Field>
+      <Field>@string/SE_who</Field>
+      <Field>@string/SE_where_t</Field>
+      <Field input_type="decimal">@string/SE_amount</Field>
+      <Field>@string/SE_msg</Field>
+    </Fields>
+    <Text>@string/SE_tx</Text>
+  </InputView>
+
+  <DialogView id="transfer_verify"
+    padding_left="2"
+    padding_right="2"
+    padding_top="1"
+    padding_bottom="1">
+    <Options>
+      <Option>@string/GENERIC_negative</Option>
+      <Option>@string/GENERIC_positive</Option>
+    </Options>
+    <Text>@string/SE_tx_verify</Text>
+  </DialogView>
+
   <!-- Session account actions -->
   <ListView id="menu_options"
     padding_left="2"
@@ -55,6 +82,10 @@
         <Text>@string/SE_view</Text>
       </ButtonView>
 
+      <ButtonView id="tx">
+        <Text>@string/SE_tx</Text>
+      </ButtonView>
+
       <ButtonView id="update">
         <Text>@string/SE_pwdu</Text>
       </ButtonView>
@@ -79,7 +110,8 @@
   <!-- Bank account list -->
   <ListView id="account_show"
     padding_left="2"
-    padding_right="2">
+    padding_right="2"
+    border="8">
     <Views>
       <ButtonView id="close">
         <Text>@string/GENERIC_dismiss</Text>
@@ -91,7 +123,8 @@
     padding_left="2"
     padding_right="2"
     padding_top="1"
-    padding_bottom="1">
+    padding_bottom="1"
+    border="11">
     <Options>
       <Option>@string/GENERIC_accept</Option>
     </Options>
diff --git a/Client/Resources/Strings/en_GB/strings.xml b/Client/Resources/Strings/en_GB/strings.xml
index 2130d33..1a31a4c 100644
--- a/Client/Resources/Strings/en_GB/strings.xml
+++ b/Client/Resources/Strings/en_GB/strings.xml
@@ -34,18 +34,32 @@ To go back, press [ESCAPE]</Entry>
 	<Entry name="SE_bal">Balance: $1</Entry>
 	<Entry name="SE_hist">Transaction history</Entry>
 	<Entry name="SE_tx">Transfer funds</Entry>
+	<Entry name="SE_tx_success">Funds transferred!</Entry>
 	<Entry name="SE_who">Send to</Entry>
 	<Entry name="SE_where">Account</Entry>
+	<Entry name="SE_where_f">From Account:</Entry>
+	<Entry name="SE_where_t">To Account:</Entry>
 	<Entry name="SE_view">View accounts</Entry>
-	<Entry name="SE_amount">Amount to transfer</Entry>
-	<Entry name="SE_msg">Include a message</Entry>
+	<Entry name="SE_amount">Amount to transfer:</Entry>
+	<Entry name="SE_tx_verify">Sending: $0 SEK
+To: $1
+To the account: $2
+Is this correct?</Entry>
+	<Entry name="SE_account_select">Select account...</Entry>
+	<Entry name="SE_user_select">Select user...</Entry>
+	<Entry name="SE_user_noselect">Please select a user!</Entry>
+	<Entry name="SE_account_noselect">Please select an account!</Entry>
+	<Entry name="SE_msg">Include a message:</Entry>
 	<Entry name="SE_pwdu">Update password</Entry>
     <Entry name="SE_exit">Log out</Entry>
     <Entry name="SE_open">Open an account</Entry>
     <Entry name="SE_close">Close an account</Entry>
     <Entry name="SE_accounts">Show accounts</Entry>
+    <Entry name="SE_balance_toohigh">Supplied balance is higher than available amount in source account!
+Available balance: $0 SEK</Entry>
+    <Entry name="SE_checking">Checking...</Entry>
     <Entry name="SE_info">Name: $0
-Balance: $1</Entry>
+Balance: $1 SEK</Entry>
 	<Entry name="SE_autolo">You were automatically logged out due to inactivity</Entry>
 	<Entry name="SE_lo">Logged out</Entry>
 	<Entry name="SE_updatestall">Updating password...</Entry>
diff --git a/Client/Resources/Strings/en_US/strings.xml b/Client/Resources/Strings/en_US/strings.xml
index 2bf4b77..c667fbb 100644
--- a/Client/Resources/Strings/en_US/strings.xml
+++ b/Client/Resources/Strings/en_US/strings.xml
@@ -20,7 +20,7 @@ To go back, press [ESCAPE]</Entry>
 	<Entry name="SU_reg">Register Account</Entry>
 	<Entry name="SU_regstall">Registering...</Entry>
 	<Entry name="SU_dup">An account with this username already exists!</Entry>
-	<Entry name="SU_mismatch">The entered passwords don't match! </Entry>
+	<Entry name="SU_mismatch">The entered passwords don't match!</Entry>
 	<Entry name="SU_weak">The password you have supplied has been deemed to be weak. Are you sure you want to continue?</Entry>
 	<Entry name="SU_login">Log in</Entry>
 	<Entry name="SU_authstall">Authenticating...</Entry>
@@ -34,18 +34,32 @@ To go back, press [ESCAPE]</Entry>
 	<Entry name="SE_bal">Balance: $1</Entry>
 	<Entry name="SE_hist">Transaction history</Entry>
 	<Entry name="SE_tx">Transfer funds</Entry>
+	<Entry name="SE_tx_success">Funds transferred!</Entry>
 	<Entry name="SE_who">Send to</Entry>
 	<Entry name="SE_where">Account</Entry>
+	<Entry name="SE_where_f">From Account:</Entry>
+	<Entry name="SE_where_t">To Account:</Entry>
 	<Entry name="SE_view">View accounts</Entry>
-	<Entry name="SE_amount">Amount to transfer</Entry>
+	<Entry name="SE_amount">Amount to transfer:</Entry>
+	<Entry name="SE_tx_verify">Sending: $0 SEK
+To: $1
+To the account: $2
+Is this correct?</Entry>
+	<Entry name="SE_account_select">Select account...</Entry>
+	<Entry name="SE_user_select">Select user...</Entry>
+	<Entry name="SE_user_noselect">Please select a user!</Entry>
+	<Entry name="SE_account_noselect">Please select an account!</Entry>
 	<Entry name="SE_msg">Include a message</Entry>
 	<Entry name="SE_pwdu">Update password</Entry>
     <Entry name="SE_exit">Log out</Entry>
     <Entry name="SE_open">Open an account</Entry>
     <Entry name="SE_close">Close an account</Entry>
     <Entry name="SE_accounts">Show accounts</Entry>
+    <Entry name="SE_balance_toohigh">Supplied balance is higher than available amount in source account!
+Available balance: $0 SEK</Entry>
+    <Entry name="SE_checking">Checking...</Entry>
     <Entry name="SE_info">Name: $0
-Balance: $1</Entry>
+Balance: $1 SEK</Entry>
 	<Entry name="SE_autolo">You were automatically logged out due to inactivity</Entry>
 	<Entry name="SE_lo">Logged out</Entry>
 	<Entry name="SE_updatestall">Updating password...</Entry>
diff --git a/Client/Resources/Strings/sv_SE/strings.xml b/Client/Resources/Strings/sv_SE/strings.xml
index 17128dd..d51fd1f 100644
--- a/Client/Resources/Strings/sv_SE/strings.xml
+++ b/Client/Resources/Strings/sv_SE/strings.xml
@@ -34,18 +34,32 @@ För att backa, tryck [ESCAPE]</Entry>
 	<Entry name="SE_bal">Kontobalans: $1</Entry>
 	<Entry name="SE_hist">Transaktionshistorik</Entry>
 	<Entry name="SE_tx">Överför pengar</Entry>
+	<Entry name="SE_tx_success">Belopp överfört!</Entry>
 	<Entry name="SE_who">Skicka till</Entry>
 	<Entry name="SE_where">Konto</Entry>
+	<Entry name="SE_where_f">Från konto:</Entry>
+	<Entry name="SE_where_t">Till konto:</Entry>
 	<Entry name="SE_view">Visa konton</Entry>
-	<Entry name="SE_amount">Värde att överföra</Entry>
+	<Entry name="SE_amount">Värde att överföra:</Entry>
+	<Entry name="SE_tx_verify">Skickar: $0 SEK
+Till: $1
+Till kontot: $2
+Är detta korrekt?</Entry>
+	<Entry name="SE_account_select">Välj konto...</Entry>
+	<Entry name="SE_user_select">Välj användare...</Entry>
+	<Entry name="SE_user_noselect">Vänligen välj en användare!</Entry>
+	<Entry name="SE_account_noselect">Vänligen välj ett konto!</Entry>
 	<Entry name="SE_msg">Inkludera ett meddelande</Entry>
 	<Entry name="SE_pwdu">Uppdatera lösenord</Entry>
     <Entry name="SE_exit">Logga ut</Entry>
     <Entry name="SE_open">Öppna ett konto</Entry>
     <Entry name="SE_close">Stäng ett konto</Entry>
     <Entry name="SE_accounts">Visa konton</Entry>
+    <Entry name="SE_balance_toohigh">Angivet belopp är högre än det tillgängliga beloppet i ursprungskontot!
+Tillgängligt saldo: $0 SEK</Entry>
+    <Entry name="SE_checking">Verifierar...</Entry>
     <Entry name="SE_info">Namn: $0
-Kontobalans: $1</Entry>
+Kontobalans: $1 SEK</Entry>
 	<Entry name="SE_autolo">Du har automatiskt loggats ut p.g.a. inaktivitet</Entry>
 	<Entry name="SE_lo">Utloggad</Entry>
 	<Entry name="SE_updatestall">Uppdaterar lösenord...</Entry>
diff --git a/Common/FixedQueue.cs b/Common/FixedQueue.cs
index bba7e81..41a5305 100644
--- a/Common/FixedQueue.cs
+++ b/Common/FixedQueue.cs
@@ -48,20 +48,25 @@ namespace Tofvesson.Common
         // Indexing for the queue
         public T ElementAt(int index) => queue[(queueStart + index) % queue.Length];
 
+        public virtual void Clear()
+        {
+            while (Count > 0) Dequeue();
+        }
+
         // Enumeration
         public virtual IEnumerator<T> GetEnumerator() => new QueueEnumerator<T>(this);
         IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 
         // Enumerator for this queue
-        public sealed class QueueEnumerator<T> : IEnumerator<T>
+        public sealed class QueueEnumerator<K> : IEnumerator<K>
         {
             private int offset = -1;
-            private readonly FixedQueue<T> queue;
+            private readonly FixedQueue<K> queue;
 
-            internal QueueEnumerator(FixedQueue<T> queue) => this.queue = queue;
+            internal QueueEnumerator(FixedQueue<K> queue) => this.queue = queue;
 
             object IEnumerator.Current => this.Current;
-            public T Current => offset == -1 ? default(T) : queue.ElementAt(offset); // Get current item or (null) if MoveNext() hasn't been called
+            public K Current => offset == -1 ? default(K) : queue.ElementAt(offset); // Get current item or (null) if MoveNext() hasn't been called
             public void Dispose() { }                                                           // NOP
             public bool MoveNext() => offset < queue.Count && ++offset < queue.Count;         // Increment index tracker (offset)
             public void Reset() => offset = -1;
diff --git a/Common/Support.cs b/Common/Support.cs
index 97d66df..60c4d95 100644
--- a/Common/Support.cs
+++ b/Common/Support.cs
@@ -235,6 +235,23 @@ namespace Tofvesson.Crypto
             return t1;
         }
 
+        public static T[] ForEach<T>(this T[] t, Func<T, T> action)
+        {
+            for (int i = 0; i < t.Length; ++i)
+                t[i] = action(t[i]);
+            return t;
+        }
+
+        // Convert an enumerable object containing strings into a readable format
+        public static string ToReadableString(this IEnumerable<string> e)
+        {
+            StringBuilder builder = new StringBuilder();
+            builder.Append('[');
+            foreach (var entry in e) builder.Append('"').Append(entry.Replace("\\", "\\\\").Replace("\"", "\\\"")).Append("\", ");
+            if (builder.Length != 1) builder.Length -= 2;
+            return builder.Append(']').ToString();
+        }
+
         /// <summary>
         /// Reads a serialized 32-bit integer from the byte collection
         /// </summary>
diff --git a/Server/Database.cs b/Server/Database.cs
index 8417843..012f5cb 100644
--- a/Server/Database.cs
+++ b/Server/Database.cs
@@ -51,16 +51,19 @@ namespace Server
         private void AddUser(User entry, bool withFlush)
         {
             for (int i = 0; i < loadedUsers.Count; ++i)
-                if (entry.Equals(loadedUsers[i]))
+                if (entry.Name.Equals(loadedUsers[i].Name))
                     loadedUsers[i] = entry;
 
             for (int i = toRemove.Count - 1; i >= 0; --i)
-                if (toRemove[i].Equals(entry.Name))
+                if (toRemove[i].Name.Equals(entry.Name))
                     toRemove.RemoveAt(i);
 
             for (int i = 0; i < changeList.Count; ++i)
-                if (changeList[i].Equals(entry.Name))
+                if (changeList[i].Name.Equals(entry.Name))
+                {
+                    changeList[i] = entry;
                     return;
+                }
 
             changeList.Add(entry);
 
@@ -94,7 +97,7 @@ namespace Server
         // Permissive (cache-dependent) flush
         private void Flush(bool optional)
         {
-            if(!(optional || changeList.Count > 30 || toRemove.Count > 30)) return; // No need to flush
+            if(optional && (changeList.Count < 30 && toRemove.Count < 30)) return; // No need to flush
             string temp = GenerateTempFileName("tmp_", ".xml");
             using(var writer = XmlWriter.Create(temp))
             {
@@ -287,7 +290,8 @@ namespace Server
             Transaction tx = new Transaction(from == null ? "System" : from.Name, to.Name, amount, message, fromAccount, toAccount);
             toAcc.History.Add(tx);
             toAcc.balance += amount;
-            AddUser(to, false);
+            AddUser(to, false); // Let's not flush unnecessarily
+            //UpdateUser(to); // For debugging: Force a flush
             if (from != null)
             {
                 fromAcc.History.Add(tx);
@@ -373,7 +377,9 @@ namespace Server
                 {
                     transaction.to = Encode(transaction.to);
                     transaction.from = Encode(transaction.from);
-                    transaction.meta = Encode(transaction.meta);
+                    if(transaction.meta != null) transaction.meta = Encode(transaction.meta);
+                    transaction.fromAccount = Encode(transaction.fromAccount);
+                    transaction.toAccount = Encode(transaction.toAccount);
                 }
             }
             return u;
@@ -391,7 +397,9 @@ namespace Server
                 {
                     transaction.to = Decode(transaction.to);
                     transaction.from = Decode(transaction.from);
-                    transaction.meta = Decode(transaction.meta);
+                    if(transaction.meta != null) transaction.meta = Decode(transaction.meta);
+                    transaction.fromAccount = Decode(transaction.fromAccount);
+                    transaction.toAccount = Decode(transaction.toAccount);
                 }
             }
             return u;
@@ -482,7 +490,11 @@ namespace Server
                 this.name = name;
             }
             public Account(Account copy) : this(copy.owner, copy.balance, copy.name)
-                => History.AddRange(copy.History);
+            {
+                // Value copy, not reference copy
+                foreach (var tx in copy.History)
+                    History.Add(new Transaction(tx.from, tx.to, tx.amount, tx.meta, tx.fromAccount, tx.toAccount));
+            }
             public Account AddTransaction(Transaction tx)
             {
                 History.Add(tx);
@@ -598,7 +610,7 @@ namespace Server
                         foreach (var accountData in entry.NestedEntries)
                         {
                             if (accountData.Name.Equals("Name")) name = accountData.Text;
-                            else if (entry.Name.Equals("Transaction"))
+                            else if (accountData.Name.Equals("Transaction"))
                             {
                                 string fromAccount = null;
                                 string toAccount = null;
@@ -606,7 +618,7 @@ namespace Server
                                 string to = null;
                                 decimal amount = -1;
                                 string meta = "";
-                                foreach (var e1 in entry.NestedEntries)
+                                foreach (var e1 in accountData.NestedEntries)
                                 {
                                     if (e1.Name.Equals("To")) to = e1.Text;
                                     else if (e1.Name.Equals("From")) from = e1.Text;
@@ -625,7 +637,7 @@ namespace Server
                                     user.ProblematicTransactions = true;
                                 else history.Add(new Transaction(from, to, amount, meta, fromAccount, toAccount));
                             }
-                            else if (entry.Name.Equals("Balance")) balance = decimal.TryParse(entry.Text, out decimal l) ? l : 0;
+                            else if (accountData.Name.Equals("Balance")) balance = decimal.TryParse(accountData.Text, out decimal l) ? l : 0;
                         }
                         if (name == null || balance < 0)
                         {
diff --git a/Server/Program.cs b/Server/Program.cs
index 0911895..28b5ce2 100644
--- a/Server/Program.cs
+++ b/Server/Program.cs
@@ -122,7 +122,9 @@ Use command 'help' to get a list of available commands";
             bool GetUser(string sid, out Database.User user)
             {
                 user = manager.GetUser(sid);
-                return user != null;
+                bool exists = user != null;
+                if (exists) user = db.GetUser(user.Name);
+                return exists && user!=null;
             }
 
             bool GetAccount(string name, Database.User user, out Database.Account acc)
@@ -188,7 +190,7 @@ Use command 'help' to get a list of available commands";
                                 }
                                 manager.Refresh(cmd[1]);
                                 StringBuilder builder = new StringBuilder();
-                                db.Users(u => { if(u.IsAdministrator || u!=user) builder.Append(u.Name.ToBase64String()).Append('&'); return false; });
+                                db.Users(u => { if(u.IsAdministrator || !u.Name.Equals(user)) builder.Append(u.Name.ToBase64String()).Append('&'); return false; });
                                 if (builder.Length != 0) --builder.Length;
                                 return GenerateResponse(id, builder);
                             }
@@ -197,7 +199,7 @@ Use command 'help' to get a list of available commands";
                                 if (!GetUser(cmd[1], out var user))
                                 {
                                     if (verbosity > 0) Output.Error("Recieved a bad session id!");
-                                    return ErrorResponse(id, "badsession");
+                                    return ErrorResponse(id, "baduser");
                                 }
                                 manager.Refresh(cmd[1]);
                                 StringBuilder builder = new StringBuilder();
@@ -243,18 +245,18 @@ Use command 'help' to get a list of available commands";
                                     error += "notargetusr";     // Target user could not be found
                                 else if (!GetAccount(data[3], tUser = db.GetUser(data[2]), out tAccount))
                                     error += "notargetacc";     // Target account could not be found
-                                else if ((!user.IsAdministrator && (systemInsert = (data[2].Equals(user.Name) && account.name.Equals(tAccount.name)))))
+                                else if ((systemInsert = (data[2].Equals(user.Name) && account.name.Equals(tAccount.name))) && (!user.IsAdministrator))
                                     error += "unprivsysins";    // Unprivileged request for system-sourced transfer
                                 else if (!decimal.TryParse(data[4], out amount) || amount < 0)
                                     error += "badbalance";      // Given sum was not a valid amount
-                                else if ((!systemInsert && amount > account.balance))
+                                else if ((!user.IsAdministrator && !systemInsert && amount > account.balance))
                                     error += "insufficient";    // Insufficient funds in the source account
                                 
                                 // Checks if an error ocurred and handles such a situation appropriately
                                 if(!error.Equals(VERBOSE_RESPONSE))
                                 {
                                     // Don't print input data to output in case sensitive information was included
-                                    Output.Error($"Recieved problematic transaction data ({error}): {data?.ToList().ToString() ?? "Data could not be parsed"}");
+                                    Output.Error($"Recieved problematic transaction data ({error}): {data?.ToList().ToReadableString() ?? "Data could not be parsed"}");
                                     return ErrorResponse(id, error);
                                 }
                                 // At this point, we know that all parsed variables above were successfully parsed and valid, therefore: no NREs
@@ -298,14 +300,13 @@ Use command 'help' to get a list of available commands";
                                 Database.Account account = null;
                                 if (!ParseDataPair(cmd[1], out string session, out string name) || // Get session id and account name
                                     !GetUser(session, out user) || // Get user associated with session id
-                                    !GetAccount(name, user, out account) ||
-                                    account.balance != 0)
+                                    !GetAccount(name, user, out account))
                                 {
                                     // Don't print input data to output in case sensitive information was included
                                     Output.Error($"Recieved problematic session id or account name!");
 
                                     // Possible errors: bad session id, bad account name, balance in account isn't 0
-                                    return ErrorResponse(id, (user == null ? "badsession" : account == null ? "badacc" : "hasbal"));
+                                    return ErrorResponse(id, (user == null ? "badsession" : account == null ? "badacc" : "badmsg"));
                                 }
                                 manager.Refresh(session);
                                 // Response example: "123.45{Sm9obiBEb2U=&Sm9obnMgQWNjb3VudA==&SmFuZSBEb2U=&SmFuZXMgQWNjb3VudA==&123.45&SGV5IHRoZXJlIQ=="
@@ -514,6 +515,9 @@ Use command 'help' to get a list of available commands";
 
             // Stop the server (obviously)
             server.StopRunning();
+
+            // Flush database
+            //db.Flush();
         }
 
         // Handles unexpected console close events (kernel event hook for window close event)