mirror of
https://github.com/ZmnSCPxj/clboss.git
synced 2026-08-14 12:43:19 +02:00
208 lines
4.9 KiB
C++
208 lines
4.9 KiB
C++
#include"Boss/Mod/SwapReporter.hpp"
|
|
#include"Boss/Msg/CommandRequest.hpp"
|
|
#include"Boss/Msg/CommandResponse.hpp"
|
|
#include"Boss/Msg/DbResource.hpp"
|
|
#include"Boss/Msg/ManifestCommand.hpp"
|
|
#include"Boss/Msg/Manifestation.hpp"
|
|
#include"Boss/Msg/ProvideStatus.hpp"
|
|
#include"Boss/Msg/SolicitStatus.hpp"
|
|
#include"Boss/Msg/SwapCompleted.hpp"
|
|
#include"Ev/Io.hpp"
|
|
#include"Ev/now.hpp"
|
|
#include"Json/Out.hpp"
|
|
#include"S/Bus.hpp"
|
|
#include"Sqlite3.hpp"
|
|
#include"Util/date.hpp"
|
|
#include"Util/make_unique.hpp"
|
|
|
|
namespace Boss { namespace Mod {
|
|
|
|
class SwapReporter::Impl {
|
|
private:
|
|
S::Bus& bus;
|
|
Sqlite3::Db db;
|
|
|
|
void start() {
|
|
bus.subscribe<Msg::DbResource
|
|
>([this](Msg::DbResource const& m) {
|
|
db = m.db;
|
|
return db.transact().then([](Sqlite3::Tx tx) {
|
|
tx.query_execute(R"QRY(
|
|
CREATE TABLE IF NOT EXISTS
|
|
"SwapReporter"
|
|
( id INTEGER PRIMARY KEY
|
|
, time REAL NOT NULL
|
|
, amount_sent INTEGER NOT NULL
|
|
, amount_received INTEGER NOT NULL
|
|
, provider_name TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS
|
|
"SwapReporter_time_idx"
|
|
ON "SwapReporter"(time)
|
|
;
|
|
)QRY");
|
|
|
|
tx.commit();
|
|
return Ev::lift();
|
|
});
|
|
});
|
|
bus.subscribe<Msg::SwapCompleted
|
|
>([](Msg::SwapCompleted const& m) {
|
|
/* Record it in our own table, using the transaction
|
|
* that SwapManager is keeping open.
|
|
*/
|
|
m.dbtx->query(R"QRY(
|
|
INSERT INTO "SwapReporter"
|
|
VALUES( NULL -- id, autogenerated
|
|
, :time
|
|
, :amount_sent
|
|
, :amount_received
|
|
, :provider_name
|
|
);
|
|
)QRY")
|
|
.bind(":time", Ev::now())
|
|
.bind( ":amount_sent"
|
|
, m.amount_sent.to_msat()
|
|
)
|
|
.bind( ":amount_received"
|
|
, m.amount_received.to_msat()
|
|
)
|
|
.bind( ":provider_name"
|
|
, m.provider_name
|
|
)
|
|
.execute()
|
|
;
|
|
return Ev::lift();
|
|
});
|
|
|
|
/* `clboss-status` */
|
|
bus.subscribe<Msg::SolicitStatus
|
|
>([this](Msg::SolicitStatus const& _) {
|
|
return db.transact().then([this](Sqlite3::Tx tx) {
|
|
auto report = make_report(tx);
|
|
tx.commit();
|
|
return bus.raise(Msg::ProvideStatus{
|
|
"swap_report",
|
|
std::move(report)
|
|
});
|
|
});
|
|
});
|
|
|
|
/* `clboss-swaps` */
|
|
bus.subscribe<Msg::Manifestation
|
|
>([this](Msg::Manifestation const& _) {
|
|
return bus.raise(Msg::ManifestCommand{
|
|
"clboss-swaps", "",
|
|
"Report about offchain-to-onchain swaps",
|
|
false
|
|
});
|
|
});
|
|
bus.subscribe<Msg::CommandRequest
|
|
>([this](Msg::CommandRequest const& r) {
|
|
if (r.command != "clboss-swaps")
|
|
return Ev::lift();
|
|
auto id = r.id;
|
|
if (!db)
|
|
return bus.raise(Msg::CommandResponse{
|
|
id,
|
|
Json::Out()
|
|
.start_object()
|
|
.field("error", "db not yet available")
|
|
.end_object()
|
|
});
|
|
return db.transact().then([this, id](Sqlite3::Tx tx) {
|
|
auto report = make_report(tx);
|
|
tx.commit();
|
|
return bus.raise(Msg::CommandResponse{
|
|
id, report
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
Json::Out make_report(Sqlite3::Tx& tx) {
|
|
auto total_amount_sent = Ln::Amount::sat(0);
|
|
auto total_amount_received = Ln::Amount::sat(0);
|
|
auto delta = Ln::Amount::sat(0);
|
|
|
|
auto percent = double();
|
|
|
|
auto rv = Json::Out();
|
|
auto obj = rv.start_object();
|
|
|
|
auto scan = tx.query(R"QRY(
|
|
SELECT time, amount_sent, amount_received, provider_name
|
|
FROM "SwapReporter"
|
|
ORDER BY time ASC;
|
|
)QRY").execute();
|
|
auto arr = obj.start_array("swaps");
|
|
for (auto& r : scan) {
|
|
auto time = r.get<double>(0);
|
|
auto amount_sent = Ln::Amount::msat(
|
|
r.get<std::uint64_t>(1)
|
|
);
|
|
auto amount_received = Ln::Amount::msat(
|
|
r.get<std::uint64_t>(2)
|
|
);
|
|
auto amount_lost = amount_sent - amount_received;
|
|
auto provider_name = r.get<std::string>(3);
|
|
total_amount_sent += amount_sent;
|
|
total_amount_received += amount_received;
|
|
|
|
arr
|
|
.start_object()
|
|
.field("time", time)
|
|
.field("time_human", Util::date(time))
|
|
.field( "amount_sent"
|
|
, std::string(amount_sent)
|
|
)
|
|
.field( "amount_received"
|
|
, std::string(amount_received)
|
|
)
|
|
.field( "amount_lost"
|
|
, std::string(amount_lost)
|
|
)
|
|
.field("provider", provider_name)
|
|
.end_object()
|
|
;
|
|
}
|
|
arr.end_array();
|
|
|
|
delta = total_amount_sent - total_amount_received;
|
|
if (total_amount_sent > Ln::Amount::sat(0))
|
|
percent = 100.0 * (delta / total_amount_sent);
|
|
|
|
obj
|
|
.field( "total_amount_sent"
|
|
, std::string(total_amount_sent)
|
|
)
|
|
.field( "total_amount_received"
|
|
, std::string(total_amount_received)
|
|
)
|
|
.field( "loss"
|
|
, std::string(delta)
|
|
)
|
|
.field( "percent_loss"
|
|
, percent
|
|
)
|
|
;
|
|
obj.end_object();
|
|
|
|
return rv;
|
|
}
|
|
|
|
public:
|
|
Impl() =delete;
|
|
Impl(Impl&&) =delete;
|
|
|
|
explicit
|
|
Impl(S::Bus& bus_) : bus(bus_) { start(); }
|
|
};
|
|
|
|
SwapReporter::SwapReporter(SwapReporter&&) =default;
|
|
SwapReporter::~SwapReporter() =default;
|
|
|
|
SwapReporter::SwapReporter(S::Bus& bus)
|
|
: pimpl(Util::make_unique<Impl>(bus)) { }
|
|
|
|
}}
|