Update lwsf version, and add some crude subaddress checking

This commit is contained in:
Lee Clagett
2025-04-18 22:23:42 -04:00
parent 4a6793608c
commit e7f1550808
8 changed files with 126 additions and 39 deletions
+1 -1
+1
View File
@@ -33,4 +33,5 @@ namespace lwcli { namespace event
/* Keep under 15 characters so that libstdc++ and libc++ can use small
string optmization. */
const ftxui::Event lock_wallet = ftxui::Event::Special("lwcli.lockw");
const ftxui::Event refresh_wallet = ftxui::Event::Special("lwcli.refresh");
}}
+1
View File
@@ -45,5 +45,6 @@ namespace lwcli { namespace event
};
extern const ftxui::Event lock_wallet;
extern const ftxui::Event refresh_wallet;
}} // lwcli // event
+27 -4
View File
@@ -37,6 +37,18 @@ namespace lwcli { namespace config
{
inline Monero::NetworkType network = Monero::MAINNET;
//! Max length for small-string optimization expectations
constexpr const unsigned sso_max = 15;
//! \return True if `str` passes sso requirements.
constexpr bool verify_sso(const std::string_view str) noexcept
{ return str.size() <= sso_max; }
//! \return True if all `strs` pass sso requirements.
template<typename... T>
constexpr bool verify_sso(const T... strs) noexcept
{ return ( ... && verify_sso(strs)); }
constexpr const std::string_view default_language{"English"};
//! Timeout interval for inactivity with open wallet
@@ -46,9 +58,20 @@ namespace lwcli { namespace config
constexpr const std::string_view default_url{"http://127.0.0.1:8080"};
constexpr const std::chrono::seconds default_refresh_interval{30};
constexpr const std::string_view proxy{"lwcli.server.proxy"};
constexpr const std::string_view refresh_interval{"lwcli.server.refresh_interval"};
constexpr const std::string_view ssl{"lwcli.server.ssl"};
constexpr const std::string_view url{"lwcli.server.url"};
constexpr const std::string_view proxy{"lwcli.ser.proxy"};
constexpr const std::string_view refresh_interval{"lwcli.ser.refr"};
constexpr const std::string_view ssl{"lwcli.ser.ssl"};
constexpr const std::string_view url{"lwcli.ser.url"};
static_assert(verify_sso(proxy, refresh_interval, ssl, url));
}
constexpr const std::uint32_t default_major_lookahead = 50;
constexpr const std::uint32_t default_minor_lookahead = 200;
constexpr const std::string_view major_lookahead{"lwcli.wal.maj_l"};
constexpr const std::string_view minor_lookahead{"lwcli.wal.min_l"};
static_assert(verify_sso(major_lookahead, minor_lookahead));
}} // lwcli // config
+5 -3
View File
@@ -282,7 +282,7 @@ namespace lwcli { namespace view
// perform transalation lookup once
base_rows = {
{_("Date"), _("Amount"), _("Payment ID"), _("Desription"), _("Block"), _("Fee"), _("Hash (abbr)")},
{_("Date"), _("Amount"), _("Payment ID"), _("Desription"), _("Block"), _("Fee"), _("Hash")},
{ "", "", "", "", "", "", "" }
};
}
@@ -397,14 +397,16 @@ namespace lwcli { namespace view
if (payment_id.size() == 16 && payment_id.find_first_not_of('0') == std::string::npos)
payment_id.clear();
char const* const extended_payment_id = 16 < payment_id.size() ?
"..." : "";
rows.push_back({
std::string{date},
print_amount(amount, direction),
payment_id.substr(0, 16),
payment_id.substr(0, 16) + extended_payment_id,
tx->description(),
std::to_string(tx->blockHeight()),
print_money(tx->fee()),
tx->hash().substr(0, 16)
tx->hash().substr(0, 16) + "..."
});
++i;
+15 -4
View File
@@ -117,9 +117,10 @@ namespace lwcli { namespace view
std::string server;
std::string proxy;
bool ssl;
bool subaddresses;
new_wallet(std::string default_file)
: wallet_base(std::move(default_file)), confirm(), language(config::default_language), server(config::server::default_url), proxy(), ssl(false)
: wallet_base(std::move(default_file)), confirm(), language(config::default_language), server(config::server::default_url), proxy(), ssl(false), subaddresses(true)
{}
void setup(Monero::Wallet& wal)
@@ -128,6 +129,15 @@ namespace lwcli { namespace view
wal.setCacheAttribute(std::string{config::server::url}, server);
wal.setCacheAttribute(std::string{config::server::proxy}, proxy);
wal.setCacheAttribute(std::string{config::server::ssl}, std::to_string(int(ssl)));
const std::uint32_t major_lookahead = subaddresses ?
config::default_major_lookahead : 0;
const std::uint32_t minor_lookahead = subaddresses ?
config::default_minor_lookahead : 0;
wal.setCacheAttribute(std::string{config::major_lookahead}, std::to_string(major_lookahead));
wal.setCacheAttribute(std::string{config::minor_lookahead}, std::to_string(minor_lookahead));
wal.setSubaddressLookahead(major_lookahead, minor_lookahead);
}
};
@@ -239,6 +249,7 @@ namespace lwcli { namespace view
enclosed->config.password.clear();
enclosed->config.confirm.clear();
enclosed->state->overlay = view::keys(prepped, true /* show warning */);
prepped->startRefresh();
enclosed->state->wal = prepped;
}
}
@@ -260,7 +271,7 @@ namespace lwcli { namespace view
{ftxui::text(_("Language: ")), last_input(&enclosed->config.language)},
{ftxui::text(_("API Server: ")), last_input(&enclosed->config.server)},
{ftxui::text(_("Proxy: ")), last_input(&enclosed->config.proxy)},
{ftxui::text(_("Options: ")), ftxui::Checkbox(_("TLS/SSL Cert Check"), &enclosed->config.ssl)}
{ftxui::text(_("Options: ")), ftxui::Container::Horizontal({ftxui::Checkbox(_("TLS/SSL Cert Check "), &enclosed->config.ssl), ftxui::Checkbox(_("Subaddresses"), &enclosed->config.subaddresses)})}
},
create
};
@@ -335,7 +346,7 @@ namespace lwcli { namespace view
{ftxui::text(_("Height: ")), last_input(&enclosed->height)},
{ftxui::text(_("API Server: ")), last_input(&enclosed->config.server)},
{ftxui::text(_("Proxy: ")), last_input(&enclosed->config.proxy)},
{ftxui::text(_("Options: ")), ftxui::Checkbox(_("TLS/SSL Cert Check"), &enclosed->config.ssl)}
{ftxui::text(_("Options: ")), ftxui::Container::Horizontal({ftxui::Checkbox(_("TLS/SSL Cert Check "), &enclosed->config.ssl), ftxui::Checkbox(_("Subaddresses"), &enclosed->config.subaddresses)})}
},
recover
};
@@ -421,7 +432,7 @@ namespace lwcli { namespace view
{ftxui::text(_("Language: ")), last_input(&enclosed->config.language)},
{ftxui::text(_("API Server: ")), last_input(&enclosed->config.server)},
{ftxui::text(_("Proxy: ")), last_input(&enclosed->config.proxy)},
{ftxui::text(_("Options: ")), ftxui::Checkbox(_("TLS/SSL Cert Check"), &enclosed->config.ssl)}
{ftxui::text(_("Options: ")), ftxui::Container::Horizontal({ftxui::Checkbox(_("TLS/SSL Cert Check "), &enclosed->config.ssl), ftxui::Checkbox(_("Subaddresses"), &enclosed->config.subaddresses)})}
},
recover
};
+34 -13
View File
@@ -38,6 +38,7 @@
#include "events.h"
#include "lwcli_config.h"
#include "translate.h"
#include "util.h"
#include "views/history.h"
@@ -45,16 +46,6 @@ namespace lwcli { namespace view
{
namespace
{
std::optional<std::uint64_t> from_string(const std::string_view str) noexcept
{
std::uint64_t out = 0;
const auto end = str.data() + str.size();
auto [ptr, ec] = std::from_chars(str.data(), end, out);
if (bool(ec) || ptr != end)
return std::nullopt;
return out;
}
bool set_proxy(Monero::Wallet& wal, const std::string& proxy)
{
wal.setProxy(proxy);
@@ -88,6 +79,34 @@ namespace lwcli { namespace view
return true;
}
bool set_major_lookahead(Monero::Wallet& wal, const std::string& major)
{
const auto major_integer = from_string(major);
if (!major_integer)
return false;
auto minor = from_string(wal.getCacheAttribute(std::string{config::minor_lookahead}));
if (!minor)
minor = config::default_minor_lookahead;
wal.setSubaddressLookahead(*major_integer, *minor);
return true;
}
bool set_minor_lookahead(Monero::Wallet& wal, const std::string& minor)
{
const auto minor_integer = from_string(minor);
if (!minor_integer)
return false;
auto major = from_string(wal.getCacheAttribute(std::string{config::major_lookahead}));
if (!major)
major = config::default_major_lookahead;
wal.setSubaddressLookahead(*major, *minor_integer);
return true;
}
struct option
{
using updater = bool(Monero::Wallet&, const std::string&);
@@ -96,11 +115,13 @@ namespace lwcli { namespace view
updater* const update;
};
const std::array<option, 4> options{{
{config::server::proxy, _("Proxy"), set_proxy},
const std::array<option, 6> options{{
{config::server::url, _("API Server"), set_url},
{config::server::refresh_interval, _("Refresh Interval (seconds)"), set_refresh},
{config::server::ssl, _("TLS/SSL Cert Check"), set_ssl},
{config::server::url, _("API Server"), set_url}
{config::server::proxy, _("Proxy"), set_proxy},
{config::major_lookahead, _("Subaddress Major Lookahead"), set_major_lookahead},
{config::minor_lookahead, _("Subaddress Minor Lookahead"), set_minor_lookahead}
}};
ftxui::Component last_input(std::string* str)
+42 -14
View File
@@ -31,6 +31,7 @@
#include <charconv>
#include <ftxui/component/component.hpp>
#include <ftxui/component/event.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/table.hpp>
#include <lws_frontend.h>
@@ -58,14 +59,14 @@ namespace lwcli { namespace view
const std::shared_ptr<Monero::Wallet> wal = state->wal;
return ftxui::Container::Horizontal({
ftxui::Button("[s]end", [] () {}, ascii()),
ftxui::Button("address [b]ook", [] () {}, ascii()),
ftxui::Button("[b]ook", [] () {}, ascii()),
ftxui::Button("[a]ccounts", [] () {}, ascii()),
ftxui::Button("[r]efresh", [wal] () { wal->refreshAsync(); }, ascii()),
ftxui::Button("s[e]ttings", [state] () { state->overlay = settings(state->wal); }, ascii())
});
}
class wallet_ final : public ftxui::ComponentBase
class wallet_ final : public ftxui::ComponentBase, Monero::WalletListener
{
wallet_state state_;
ftxui::Element title_;
@@ -83,6 +84,28 @@ namespace lwcli { namespace view
return ui_;
}
void moneySpent(const std::string &txId, uint64_t amount) override final
{}
void moneyReceived(const std::string &txId, uint64_t amount) override final
{}
void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override final
{}
void newBlock(uint64_t height) override final
{}
void updated() override final
{}
void refreshed() override final
{
ftxui::ScreenInteractive* const active = ftxui::ScreenInteractive::Active();
if (active)
active->PostEvent(event::refresh_wallet);
}
public:
explicit wallet_(std::shared_ptr<Monero::Wallet>&& data)
: ftxui::ComponentBase(),
@@ -96,11 +119,17 @@ namespace lwcli { namespace view
{
if (!state_.wal)
throw std::runtime_error{"Unexpected nullptr Monero wallet"};
state_.wal->setListener(this);
bar_ = menu_bar(&state_);
title_ = ftxui::text(_("lwcli Wallet (Primary ") + state_.wal->mainAddress() + ")");
update_account();
}
virtual ~wallet_() noexcept override final
{
state_.wal->setListener(nullptr);
}
void update_account()
{
if (active_account_ != selected_account_)
@@ -120,7 +149,9 @@ namespace lwcli { namespace view
{
const bool has_overlay = bool(state_.overlay);
if (state_.overlay)
if (event == event::refresh_wallet)
return true;
else if (state_.overlay)
state_.overlay->OnEvent(std::move(event));
else if (event == ftxui::Event::CtrlQ)
throw event::close{};
@@ -159,16 +190,13 @@ namespace lwcli { namespace view
const bool connected =
state_.wal->connected() == Monero::Wallet::ConnectionStatus_Connected;
std::string status;
if (!connected)
{
status = "Disconnected";
const std::string& error = state_.wal->errorString();
if (!error.empty())
status += ": " + error;
}
else
status = "Connected";
int status = 0;
std::string error;
state_.wal->statusWithErrorString(status, error);
std::string message = connected ? "Connected" : "Disconnected";
if (status != Monero::Wallet::Status_Ok)
message.append(": ").append(error);
auto screen = ftxui::vbox({
title_,
@@ -176,7 +204,7 @@ namespace lwcli { namespace view
ftxui::separator(),
history_->Render() | ftxui::yflex_shrink,
ftxui::filler(),
ftxui::inverted(decorate::banner(ftxui::text(std::move(status))))
ftxui::inverted(decorate::banner(ftxui::text(std::move(message))))
});
if (state_.overlay)