Jelajahi Sumber

app/wallet: improve tx_status

x 2 minggu lalu
induk
melakukan
6ab21beebb
3 mengubah file dengan 326 tambahan dan 101 penghapusan
  1. 311 59
      bin/app/src/app/schema/wallet/tx_status.rs
  2. 6 6
      bin/app/src/main.rs
  3. 9 36
      bin/app/src/plugin/drk.rs

+ 311 - 59
bin/app/src/app/schema/wallet/tx_status.rs

@@ -23,17 +23,18 @@ use darkfi_serial::Decodable;
 
 use crate::{
     app::{
-        node::{create_layer, create_text},
+        node::{create_layer, create_text, create_vector_art},
         App,
     },
     expr,
     gfx::gfxtag,
+    mesh::{COLOR_DARKTEAL, COLOR_GREEN, COLOR_RED},
     prop::{
         Property, PropertyAtomicGuard, PropertyBool, PropertyFloat32, PropertyPermission,
         PropertySubType, PropertyType, Role,
     },
     scene::{SceneNodePtr, Slot},
-    ui::{Layer, Text},
+    ui::{Layer, Text, VectorArt, VectorShape},
     util::i18n::I18nBabelFish,
 };
 
@@ -55,6 +56,7 @@ pub async fn make(
     cc.add_const_f32("AMOUNT_FONTSIZE", AMOUNT_FONTSIZE);
     cc.add_const_f32("BASE_FONTSIZE", BASE_FONTSIZE);
     cc.add_const_f32("HINT_FONTSIZE", HINT_FONTSIZE);
+    cc.add_const_f32("HINT_H", HINT_H);
     cc.add_const_f32("PADDING_X", PADDING_X);
     cc.add_const_f32("PADDING_Y", PADDING_Y);
     cc.add_const_f32("RECIPIENT_INPUT_MARGIN", RECIPIENT_INPUT_MARGIN);
@@ -100,6 +102,29 @@ pub async fn make(
     prop.set_defaults_str(vec!["".to_string()]).unwrap();
     tx_status_layer.add_property(prop).unwrap();
 
+    // Add tx_id property to store the transaction ID for status polling
+    let mut prop = Property::new(
+        "tx_status",
+        PropertyType::Enum,
+        PropertySubType::Null,
+        PropertyPermission::default(),
+    );
+    prop.set_enum_items(vec!["confirming", "confirmed", "error"]).unwrap();
+    prop.set_default_enum(0, "confirming").unwrap();
+    tx_status_layer.add_property(prop).unwrap();
+
+    // Height of the hint zone
+    const HINT_H: f32 = PADDING_X + PADDING_Y + HINT_FONTSIZE * 2.;
+    let mut prop = Property::new(
+        "hint_h",
+        PropertyType::Float32,
+        PropertySubType::Pixel,
+        PropertyPermission::default(),
+    );
+    prop.set_defaults_f32(vec![HINT_H]).unwrap();
+    tx_status_layer.add_property(prop).unwrap();
+    let hint_h_prop = tx_status_layer.get_property("hint_h").unwrap();
+
     let prop = tx_status_layer.get_property("rect").unwrap();
     prop.set_default_f32(0, 0.).unwrap();
     prop.set_default_f32(1, 0.).unwrap();
@@ -117,20 +142,16 @@ pub async fn make(
 
     create_bg_mesh(app, atom, &tx_status_layer, "tx_status_bg").await;
 
-    let mut y = HEADER_HEIGHT;
-
-    create_title(app, atom, &tx_status_layer, &window_scale, i18n_fish, "SEND", "SEND", &mut y)
-        .await;
-
-    // Status text
+    // Status headline
     let node = create_text("status");
     let prop = node.get_property("rect").unwrap();
-    prop.set_default_f32(0, PADDING_X).unwrap();
-    prop.set_default_f32(1, y + PADDING_Y).unwrap();
-    prop.set_default_f32(2, 1000.).unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    prop.set_default_f32(1, HEADER_HEIGHT + PADDING_Y).unwrap();
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
     prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
     node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
-    node.set_property_str(atom, Role::App, "text", "Broadcasting...").unwrap();
+    node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
+    node.set_property_str(atom, Role::App, "text", "Transaction in process...").unwrap();
     let prop = node.get_property("text_color").unwrap();
     prop.set_default_f32_multi(&[1., 1., 1., 1.]).unwrap();
     node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
@@ -147,22 +168,76 @@ pub async fn make(
         .await;
     tx_status_layer.link(node);
 
-    y += PADDING_Y * 2. + BASE_FONTSIZE + 1.;
+    // Transaction info: "Sending" / "{amount} {token_symbol}" / "to" / "{recipient}"
+    // stacked below each other, centered horizontally, inside a layer that is
+    // vertically centered in the free space below the header.
+    let info_h = PADDING_Y * 5. + BASE_FONTSIZE * 4. + 1.;
+    cc.add_const_f32("TX_TOP", HEADER_HEIGHT);
+    let tx_info_layer = create_layer("tx_info");
+    tx_info_layer.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
+    let prop = tx_info_layer.get_property("rect").unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    let code = cc
+        .compile(
+            "
+        info_h = PADDING_Y * 5 + BASE_FONTSIZE * 4 + 1;
+        free_h = h - PADDING_X * 2 - BUTTON_HEIGHT - hint_h - TX_TOP;
+        if free_h < info_h {
+            TX_TOP
+        } else {
+            TX_TOP + (free_h - info_h) / 2
+        }
+        ",
+        )
+        .unwrap();
+    prop.set_default_expr(1, code).unwrap();
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
+    prop.set_default_f32(3, info_h).unwrap();
+    prop.add_depend(Role::App, &hint_h_prop, 0, "hint_h");
+    tx_info_layer.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
+    let tx_info_layer = tx_info_layer
+        .setup(|me| Layer::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
+        .await;
+    tx_status_layer.link(tx_info_layer.clone());
 
-    create_separator(&app, atom, &tx_status_layer, "tx_status_separator", &mut y, false).await;
+    // Inset box shadow
+    let shadow_node = create_vector_art("tx_status_shadow");
+    let prop = shadow_node.get_property("rect").unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    prop.set_default_expr(1, cc.compile("TX_TOP").unwrap()).unwrap();
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
+    prop.set_default_expr(
+        3,
+        cc.compile("h - PADDING_X * 2 - BUTTON_HEIGHT - TX_TOP - hint_h").unwrap(),
+    )
+    .unwrap();
+    prop.add_depend(Role::App, &hint_h_prop, 0, "hint_h");
+    shadow_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
+    let shadow_node = shadow_node
+        .setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
+        .await;
+    let mut shadow_shape = VectorShape::new();
+    shadow_shape.add_box_shadow_inset(
+        expr::const_f32(0.),
+        expr::const_f32(0.),
+        expr::load_var("w"),
+        expr::load_var("h"),
+        100.,
+        [0., 0., 0., 0.],
+    );
+    shadow_node.set_property_shape(atom, Role::App, "shape", shadow_shape).unwrap();
+    tx_status_layer.link(shadow_node);
 
-    // Transaction info text: "Sending {amount} {token_symbol} to {recipient_address}"
-    let node = create_text("tx_info");
-    let info_h_prop = node.get_property("height").unwrap();
+    // "Sending" or "Sent"
+    let node = create_text("action");
     let prop = node.get_property("rect").unwrap();
-    prop.set_default_f32(0, PADDING_X).unwrap();
-    prop.set_default_f32(1, y + PADDING_Y).unwrap();
-    let code = cc.compile("w - PADDING_X * 2").unwrap();
-    prop.set_default_expr(2, code).unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    prop.set_default_f32(1, PADDING_Y).unwrap();
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
     prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
     node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
-    node.set_property_str(atom, Role::App, "text", "Sending 0 DRK to recipient").unwrap();
-    node.set_property_enum(atom, Role::App, "overflow_wrap", "anywhere").unwrap();
+    node.set_property_str(atom, Role::App, "text", "Sending").unwrap();
+    node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
     let prop = node.get_property("text_color").unwrap();
     prop.set_default_f32_multi(&[1., 1., 1., 1.]).unwrap();
     node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
@@ -177,29 +252,119 @@ pub async fn make(
             )
         })
         .await;
-    tx_status_layer.link(node);
+    tx_info_layer.link(node);
 
-    let sep = create_separator(
-        app,
-        atom,
-        &tx_status_layer,
-        "tx_info_separator",
-        &mut 0.,
-        false,
-    )
-    .await;
-    let prop = sep.get_property("rect").unwrap();
-    let code = cc.compile(format!("{y} + PADDING_Y * 2 + info_height + 1")).unwrap();
+    // Amount + token symbol
+    let node = create_text("amount");
+    let prop = node.get_property("rect").unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    let code = cc.compile("PADDING_Y * 2 + BASE_FONTSIZE").unwrap();
+    prop.set_default_expr(1, code).unwrap();
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
+    prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
+    node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
+    node.set_property_str(atom, Role::App, "text", "").unwrap();
+    node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
+    let prop = node.get_property("text_color").unwrap();
+    prop.set_default_f32_multi(&[0.5451, 1., 1., 1.]).unwrap();
+    let prop = node.get_property("text_shadow_color").unwrap();
+    prop.set_default_f32_multi(&[0.5451, 1., 1., 1.]).unwrap();
+    let prop = node.get_property("text_shadow_blur").unwrap();
+    prop.set_default_f32(0, BASE_FONTSIZE / 2.).unwrap();
+    node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
+    let node = node
+        .setup(|me| {
+            Text::new(
+                me,
+                window_scale.clone(),
+                app.renderer.clone(),
+                i18n_fish.clone(),
+                app.redraw_trigger.clone(),
+            )
+        })
+        .await;
+    tx_info_layer.link(node);
+
+    // "to"
+    let node = create_text("to");
+    let prop = node.get_property("rect").unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    let code = cc.compile("PADDING_Y * 3 + BASE_FONTSIZE * 2").unwrap();
+    prop.set_default_expr(1, code).unwrap();
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
+    prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
+    node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
+    node.set_property_str(atom, Role::App, "text", "to").unwrap();
+    node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
+    let prop = node.get_property("text_color").unwrap();
+    prop.set_default_f32_multi(&[1., 1., 1., 1.]).unwrap();
+    node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
+    let node = node
+        .setup(|me| {
+            Text::new(
+                me,
+                window_scale.clone(),
+                app.renderer.clone(),
+                i18n_fish.clone(),
+                app.redraw_trigger.clone(),
+            )
+        })
+        .await;
+    tx_info_layer.link(node);
+
+    // Recipient address
+    let node = create_text("recipient");
+    let prop = node.get_property("rect").unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    let code = cc.compile("PADDING_Y * 4 + BASE_FONTSIZE * 3").unwrap();
     prop.set_default_expr(1, code).unwrap();
-    prop.add_depend(Role::App, &info_h_prop, 0, "info_height");
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
+    prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
+    node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
+    node.set_property_str(atom, Role::App, "text", "").unwrap();
+    node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
+    node.set_property_enum(atom, Role::App, "overflow_wrap", "anywhere").unwrap();
+    let prop = node.get_property("text_color").unwrap();
+    prop.set_default_f32_multi(&[0., 1., 0.6392, 1.]).unwrap();
+    let prop = node.get_property("text_shadow_color").unwrap();
+    prop.set_default_f32_multi(&[0., 1., 0.6392, 1.]).unwrap();
+    let prop = node.get_property("text_shadow_blur").unwrap();
+    prop.set_default_f32(0, BASE_FONTSIZE / 2.).unwrap();
+    node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
+    let node = node
+        .setup(|me| {
+            Text::new(
+                me,
+                window_scale.clone(),
+                app.renderer.clone(),
+                i18n_fish.clone(),
+                app.redraw_trigger.clone(),
+            )
+        })
+        .await;
+    tx_info_layer.link(node);
+
+    // Hint text. Only shown while the tx is confirming (see the
+    // "tx_status" property subscription below). Wrapped in its own layer
+    // since Text has no is_visible property.
+    let hint_layer = create_layer("hint_layer");
+    hint_layer.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
+    let prop = hint_layer.get_property("rect").unwrap();
+    prop.set_default_f32(0, 0.).unwrap();
+    prop.set_default_f32(1, 0.).unwrap();
+    prop.set_default_expr(2, expr::load_var("w")).unwrap();
+    prop.set_default_expr(3, expr::load_var("h")).unwrap();
+    hint_layer.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
+    let hint_layer = hint_layer
+        .setup(|me| Layer::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
+        .await;
+    tx_status_layer.link(hint_layer.clone());
 
-    // Hint text
-    let hint_node = create_text("tx_status_hint");
+    let hint_node = create_text("hint");
     let prop = hint_node.get_property("rect").unwrap();
     let code = cc.compile("w / 2 - (HINT_FONTSIZE * 0.7 * 31) / 2").unwrap();
     prop.set_default_expr(0, code).unwrap();
-    let code =
-        cc.compile("h - PADDING_X * 2 - BUTTON_HEIGHT - PADDING_Y - HINT_FONTSIZE * 2").unwrap();
+    let code = cc.compile("h - PADDING_X - HINT_H + PADDING_Y").unwrap();
     prop.set_default_expr(1, code).unwrap();
     let code = cc.compile("HINT_FONTSIZE * 0.7 * 31").unwrap();
     prop.set_default_expr(2, code).unwrap();
@@ -215,7 +380,7 @@ pub async fn make(
         )
         .unwrap();
     let prop = hint_node.get_property("text_color").unwrap();
-    prop.set_default_f32_multi(&[1., 1., 1., 0.45]).unwrap();
+    prop.set_default_f32_multi(&COLOR_DARKTEAL).unwrap();
     hint_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
     let hint_node = hint_node
         .setup(|me| {
@@ -228,26 +393,29 @@ pub async fn make(
             )
         })
         .await;
-    tx_status_layer.link(hint_node.clone());
+    hint_layer.link(hint_node);
 
     // Separator line
     create_separator_expr(
         app,
         atom,
         &tx_status_layer,
-        "tx_status_hint_separator",
+        "hint_separator",
         &mut cc,
-        "h - PADDING_X * 2 - BUTTON_HEIGHT",
+        "h - PADDING_X * 2 - BUTTON_HEIGHT - hint_h",
         false,
     )
-    .await;
+    .await
+    .get_property("rect")
+    .unwrap()
+    .add_depend(Role::App, &hint_h_prop, 0, "hint_h");
 
     // Close button
     let node = create_bottom_button(
         app,
         atom,
         &tx_status_layer,
-        "tx_status_close_btn",
+        "close_btn",
         &mut cc,
         Some("close"),
         &window_scale,
@@ -255,6 +423,13 @@ pub async fn make(
     )
     .await;
 
+    // Move the button group above the hint zone
+    let btn_layer = tx_status_layer.lookup_node("/close_btn_layer").unwrap();
+    let prop = btn_layer.get_property("rect").unwrap();
+    let code = cc.compile("h - PADDING_X - BUTTON_HEIGHT - hint_h").unwrap();
+    prop.set_expr(atom, Role::App, 1, code).unwrap();
+    prop.add_depend(Role::App, &hint_h_prop, 0, "hint_h");
+
     let main_is_visible = PropertyBool::wrap(&main_layer, Role::App, "is_visible", 0).unwrap();
     let redraw = app.redraw_trigger.clone();
     let tx_status_is_visible1 = tx_status_is_visible.clone();
@@ -286,7 +461,7 @@ pub async fn make(
 
             let mut cur = std::io::Cursor::new(mcall.data);
             let tx_id = Option::<String>::decode(&mut cur).unwrap();
-            let status_text = Option::<String>::decode(&mut cur).unwrap();
+            let confirmed = Option::<bool>::decode(&mut cur).unwrap();
             let amount = Option::<String>::decode(&mut cur).unwrap();
             let token_symbol = Option::<String>::decode(&mut cur).unwrap();
             let recipient_str = Option::<String>::decode(&mut cur).unwrap();
@@ -296,25 +471,34 @@ pub async fn make(
                 tx_status_layer_clone.set_property_str(atom, Role::App, "tx_id", id).unwrap();
             }
 
-            // Update status text
-            if let Some(text) = status_text {
-                if let Some(status_node) =
-                    sg_root.lookup_node("/window/content/wallet/tx_status_layer/status")
-                {
-                    status_node.set_property_str(atom, Role::App, "text", &text).unwrap();
-                }
+            // Store the tx_status
+            if let Some(confirmed) = confirmed {
+                let status = match confirmed {
+                    false => "confirming",
+                    true => "confirmed",
+                };
+                tx_status_layer_clone
+                    .set_property_enum(atom, Role::App, "tx_status", status)
+                    .unwrap();
             }
 
             // Update transaction info display
             if let (Some(amount), Some(token_symbol), Some(recipient_str)) =
                 (amount, token_symbol, recipient_str)
             {
-                if let Some(tx_info) =
-                    sg_root.lookup_node("/window/content/wallet/tx_status_layer/tx_info")
+                if let Some(tx_info_amount) =
+                    sg_root.lookup_node("/window/content/wallet/tx_status_layer/tx_info/amount")
                 {
-                    let tx_text =
-                        format!("Sending {} {} to {}", amount, token_symbol, recipient_str);
-                    tx_info.set_property_str(atom, Role::App, "text", tx_text).unwrap();
+                    let amount_text = format!("{} {}", amount, token_symbol);
+                    tx_info_amount.set_property_str(atom, Role::App, "text", amount_text).unwrap();
+                }
+
+                if let Some(tx_info_recipient) =
+                    sg_root.lookup_node("/window/content/wallet/tx_status_layer/tx_info/recipient")
+                {
+                    tx_info_recipient
+                        .set_property_str(atom, Role::App, "text", format_address(&recipient_str))
+                        .unwrap();
                 }
             }
         }
@@ -333,5 +517,73 @@ pub async fn make(
         }
     }));
 
+    // Subscribe to the current tx status and update the screen accordingly
+    let status_prop = tx_status_layer.get_property("tx_status").unwrap();
+    let text_sub = status_prop.subscribe_modify();
+    let redraw = app.redraw_trigger.clone();
+    let shadow_node = tx_status_layer.lookup_node("/tx_status_shadow").unwrap();
+    let action_node = tx_status_layer.lookup_node("/tx_info/action").unwrap();
+    let status_node = tx_status_layer.lookup_node("/status").unwrap();
+    let hint_layer = tx_status_layer.lookup_node("/hint_layer").unwrap();
+    let hint_layer_is_visible =
+        PropertyBool::wrap(&hint_layer, Role::App, "is_visible", 0).unwrap();
+
+    let listen_status_text = {
+        let redraw = redraw.clone();
+        let shadow_node = shadow_node.clone();
+        app.ex.spawn(async move {
+            while let Ok(_) = text_sub.receive().await {
+                let atom = &mut redraw.make_guard(gfxtag!("tx status updated"));
+
+                let status = status_prop.get_enum(0).unwrap();
+
+                // Toggle hint
+                let confirming = status == "confirming";
+                hint_layer_is_visible.set(atom, confirming);
+                hint_h_prop
+                    .set_f32(atom, Role::App, 0, if confirming { HINT_H } else { 0. })
+                    .unwrap();
+
+                // Update headline text + color
+                let (headline, headline_color) = match status.as_str() {
+                    "confirmed" => ("Transaction successful", COLOR_GREEN),
+                    "error" => ("Transaction failed", COLOR_RED),
+                    _ => ("Transaction in process...", [0.5725, 1., 0.898, 1.]),
+                };
+                status_node.set_property_str(atom, Role::App, "text", headline).unwrap();
+                let prop = status_node.get_property("text_color").unwrap();
+                for i in 0..4 {
+                    prop.set_f32(atom, Role::App, i, headline_color[i]).unwrap();
+                }
+
+                // Update action text
+                let text = match status.as_str() {
+                    "confirmed" => "Sent",
+                    "error" => "Failed to send",
+                    _ => "Sending",
+                };
+                action_node.set_property_str(atom, Role::App, "text", text).unwrap();
+
+                // Shadow color follows the tx status
+                let color = match status.as_str() {
+                    "confirmed" => [COLOR_GREEN[0], COLOR_GREEN[1], COLOR_GREEN[2], 0.3],
+                    "error" => [COLOR_RED[0], COLOR_RED[1], COLOR_RED[2], 0.3],
+                    _ => [0., 0., 0., 0.],
+                };
+                let mut shape = VectorShape::new();
+                shape.add_box_shadow_inset(
+                    expr::const_f32(0.),
+                    expr::const_f32(0.),
+                    expr::load_var("w"),
+                    expr::load_var("h"),
+                    100.,
+                    color,
+                );
+                shadow_node.set_property_shape(atom, Role::App, "shape", shape).unwrap();
+            }
+        })
+    };
+    app.tasks.lock().push(listen_status_text);
+
     tx_status_layer
 }

+ 6 - 6
bin/app/src/main.rs

@@ -586,9 +586,11 @@ async fn load_plugins(
                             .unwrap();
 
                         let mut cur = std::io::Cursor::new(status_data);
-                        let status_text = String::decode(&mut cur).unwrap();
-                        let status_node = tx_status_layer.lookup_node("/status").unwrap();
-                        status_node.set_property_str(atom, Role::App, "text", status_text).unwrap();
+                        if bool::decode(&mut cur).unwrap() {
+                            tx_status_layer
+                                .set_property_enum(atom, Role::App, "tx_status", "confirmed")
+                                .unwrap();
+                        }
                     }
                 }
             };
@@ -636,9 +638,7 @@ async fn load_plugins(
                 {
                     let mut tx_status_data = vec![];
                     None::<String>.encode(&mut tx_status_data).unwrap();
-                    Some("Broadcasting transaction...".to_string())
-                        .encode(&mut tx_status_data)
-                        .unwrap();
+                    None::<bool>.encode(&mut tx_status_data).unwrap();
                     Some(amount).encode(&mut tx_status_data).unwrap();
                     Some(token_symbol).encode(&mut tx_status_data).unwrap();
                     Some(recipient_str).encode(&mut tx_status_data).unwrap();

+ 9 - 36
bin/app/src/plugin/drk.rs

@@ -100,27 +100,10 @@ macro_rules! d { ($($arg:tt)*) => { debug!(target: "plugin::drk", $($arg)*); } }
 macro_rules! i { ($($arg:tt)*) => { info!(target: "plugin::drk", $($arg)*); } }
 macro_rules! e { ($($arg:tt)*) => { error!(target: "plugin::drk", $($arg)*); } }
 
-#[derive(Debug, Clone)]
-enum TxStatus {
-    Confirming,
-    Confirmed,
-    Error(String),
-}
-
-impl TxStatus {
-    fn text(&self) -> String {
-        match self {
-            TxStatus::Confirming => "Confirming transaction...".to_string(),
-            TxStatus::Confirmed => "Transaction confirmed".to_string(),
-            TxStatus::Error(ref err) => format!("Error sending transaction: {err}"),
-        }
-    }
-}
-
 #[derive(Debug, Clone)]
 struct TxState {
     id: Option<String>,
-    status: TxStatus,
+    confirmed: bool,
     amount: Option<String>,
     token_symbol: Option<String>,
     recipient: Option<Address>,
@@ -1084,18 +1067,18 @@ impl DrkPlugin {
         if let Some(node) = self.node.upgrade() {
             let mut data = vec![];
             state.id.clone().encode(&mut data).unwrap();
-            Some(state.status.text()).encode(&mut data).unwrap();
+            Some(state.confirmed).encode(&mut data).unwrap();
             state.amount.encode(&mut data).unwrap();
             state.token_symbol.clone().encode(&mut data).unwrap();
             state.recipient.map(|r| r.to_string()).encode(&mut data).unwrap();
             let _ = node.trigger("tx_updated", data).await;
         }
     }
-    async fn emit_tx_status_updated(&self, status: &TxStatus) {
+    async fn emit_tx_status_updated(&self, confirmed: bool) {
         if let Some(node) = self.node.upgrade() {
             let mut data = vec![];
             None::<String>.encode(&mut data).unwrap();
-            Some(status.text()).encode(&mut data).unwrap();
+            Some(confirmed).encode(&mut data).unwrap();
             None::<String>.encode(&mut data).unwrap();
             None::<String>.encode(&mut data).unwrap();
             None::<String>.encode(&mut data).unwrap();
@@ -1250,12 +1233,8 @@ impl DrkPlugin {
         };
         if let Some(send_res) = method_call.send_res {
             let mut cur = Cursor::new(vec![]);
-            let status = match status.as_str() {
-                "Broadcasted" => TxStatus::Confirming,
-                "Confirmed" => TxStatus::Confirmed,
-                _ => TxStatus::Error("unknown status".to_string()),
-            };
-            if status.text().encode(&mut cur).is_ok() {
+            let confirmed = status.as_str() == "Confirmed";
+            if confirmed.encode(&mut cur).is_ok() {
                 let _ = send_res.send(cur.into_inner()).await;
             } else {
                 e!("Failed to encode tx status");
@@ -1372,20 +1351,14 @@ impl DrkPlugin {
         let drk = self_.drk.read().await;
         if let Err(e) = drk.mark_tx_spend(&tx, &mut vec![]).await {
             e!("Failed to mark transaction coins as spent: {e}");
-            self_
-                .emit_tx_status_updated(&TxStatus::Error(
-                    "failed to mark coins as spent".to_string(),
-                ))
-                .await;
+            self_.emit_tx_status_updated(false).await;
             return true
         };
         let tx_id = match drk.broadcast_tx(&tx, &mut vec![]).await {
             Ok(t) => t,
             Err(e) => {
                 e!("Failed to broadcast transaction: {e}");
-                self_
-                    .emit_tx_status_updated(&TxStatus::Error("failed to broadcast".to_string()))
-                    .await;
+                self_.emit_tx_status_updated(false).await;
                 return true
             }
         };
@@ -1393,7 +1366,7 @@ impl DrkPlugin {
 
         let state = TxState {
             id: Some(tx_id),
-            status: TxStatus::Confirming,
+            confirmed: false,
             amount: None,
             token_symbol: None,
             recipient: None,