diff --git a/Cargo.lock b/Cargo.lock
index c9d829c..fe38fd1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -984,6 +984,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"arrayvec 0.7.0",
+ "bincode",
"duniter-core",
"duniter-gva-db",
"flate2",
diff --git a/dbs-reader/Cargo.toml b/dbs-reader/Cargo.toml
index 3063442..b25a488 100644
--- a/dbs-reader/Cargo.toml
+++ b/dbs-reader/Cargo.toml
@@ -17,6 +17,7 @@ mock = ["mockall"]
[dependencies]
anyhow = "1.0.34"
arrayvec = { version = "0.7", features = ["serde"] }
+bincode = "1.3"
duniter-core = { git = "https://git.duniter.org/nodes/rust/duniter-core" }
duniter-gva-db = { path = "../db" }
flate2 = { version = "1.0", features = ["zlib-ng-compat"], default-features = false }
diff --git a/dbs-reader/src/cursors.rs b/dbs-reader/src/cursors.rs
new file mode 100644
index 0000000..b23b938
--- /dev/null
+++ b/dbs-reader/src/cursors.rs
@@ -0,0 +1,83 @@
+// Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use crate::*;
+use duniter_core::crypto::keys::ed25519::PublicKey;
+use duniter_core::crypto::keys::PublicKey as _;
+use duniter_core::dbs::WalletConditionsV2;
+
+#[derive(Clone, Copy, Debug)]
+pub struct WrongCursor;
+impl std::fmt::Display for WrongCursor {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "wrong cursor")
+ }
+}
+impl std::error::Error for WrongCursor {}
+
+pub trait Cursor:
+ 'static + Clone + std::fmt::Debug + std::fmt::Display + Default + FromStr + Ord
+{
+}
+
+#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
+pub struct PubKeyCursor(pub PublicKey);
+
+impl PubKeyCursor {
+ pub fn from_ref(pk: &PublicKey) -> &Self {
+ #[allow(trivial_casts)]
+ unsafe {
+ &*(pk as *const PublicKey as *const PubKeyCursor)
+ }
+ }
+}
+
+impl Cursor for PubKeyCursor {}
+
+impl std::fmt::Display for PubKeyCursor {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0.to_string())
+ }
+}
+
+impl FromStr for PubKeyCursor {
+ type Err = WrongCursor;
+
+ fn from_str(s: &str) -> Result {
+ if let Ok(pk) = PublicKey::from_base58(s) {
+ Ok(PubKeyCursor(pk))
+ } else {
+ Err(WrongCursor)
+ }
+ }
+}
+
+impl From for WalletConditionsV2 {
+ fn from(val: PubKeyCursor) -> Self {
+ WalletConditionsV2(WalletScriptV10::single_sig(val.0))
+ }
+}
+
+impl Ord for PubKeyCursor {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.0.as_ref().cmp(other.0.as_ref())
+ }
+}
+
+impl PartialOrd for PubKeyCursor {
+ fn partial_cmp(&self, other: &Self) -> Option {
+ self.0.as_ref().partial_cmp(other.0.as_ref())
+ }
+}
diff --git a/dbs-reader/src/lib.rs b/dbs-reader/src/lib.rs
index 98fba11..0d45be7 100644
--- a/dbs-reader/src/lib.rs
+++ b/dbs-reader/src/lib.rs
@@ -25,6 +25,7 @@
pub mod block;
pub mod blocks_chunks;
pub mod current_frame;
+pub mod cursors;
pub mod find_inputs;
pub mod idty;
pub mod network;
@@ -32,7 +33,9 @@ pub mod pagination;
pub mod txs_history;
pub mod uds_of_pubkey;
pub mod utxos;
+pub mod wallets;
+pub use crate::cursors::{Cursor, PubKeyCursor, WrongCursor};
pub use crate::pagination::{PageInfo, PagedData};
pub use duniter_core::bda_types::MAX_FIRST_UTXOS;
@@ -69,15 +72,6 @@ use std::{
str::FromStr,
};
-#[derive(Clone, Copy, Debug)]
-pub struct WrongCursor;
-impl std::fmt::Display for WrongCursor {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "wrong cursor")
- }
-}
-impl std::error::Error for WrongCursor {}
-
#[cfg_attr(feature = "mock", mockall::automock)]
pub trait DbsReader {
fn all_uds_of_pubkey(
@@ -181,6 +175,29 @@ pub trait DbsReader {
bn_to_exclude_opt: Option>,
amount_target_opt: Option,
) -> KvResult>;
+ fn wallets(
+ &self,
+ exclude_single_sig: bool,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>>;
+ fn wallets_single_sig(
+ &self,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>>;
+ fn wallets_single_sig_with_idty_opt(
+ &self,
+ bc_db: &BcV2DbRo,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>>;
+ fn wallets_with_idty_opt(
+ &self,
+ bc_db: &BcV2DbRo,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>>;
}
#[derive(Clone, Copy, Debug)]
@@ -359,6 +376,41 @@ impl DbsReader for DbsReaderImpl {
amount_target_opt,
)
}
+
+ fn wallets(
+ &self,
+ exclude_single_sig: bool,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ self.wallets_(exclude_single_sig, min_balance_opt, page_info)
+ }
+
+ fn wallets_single_sig(
+ &self,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ self.wallets_single_sig_(min_balance_opt, page_info)
+ }
+
+ fn wallets_single_sig_with_idty_opt(
+ &self,
+ bc_db: &BcV2DbRo,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ self.wallets_single_sig_with_idty_opt_(bc_db, min_balance_opt, page_info)
+ }
+
+ fn wallets_with_idty_opt(
+ &self,
+ bc_db: &BcV2DbRo,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ self.wallets_with_idty_opt_(bc_db, min_balance_opt, page_info)
+ }
}
#[cfg(test)]
diff --git a/dbs-reader/src/pagination.rs b/dbs-reader/src/pagination.rs
index 48d80bb..8cd2931 100644
--- a/dbs-reader/src/pagination.rs
+++ b/dbs-reader/src/pagination.rs
@@ -30,6 +30,19 @@ impl PagedData {
}
}
}
+impl PagedData {
+ pub fn map(self, f: F) -> PagedData
+ where
+ T: std::fmt::Debug,
+ F: FnOnce(D) -> T,
+ {
+ PagedData {
+ data: f(self.data),
+ has_previous_page: self.has_previous_page,
+ has_next_page: self.has_next_page,
+ }
+ }
+}
#[derive(Debug)]
pub struct PageInfo {
diff --git a/dbs-reader/src/wallets.rs b/dbs-reader/src/wallets.rs
new file mode 100644
index 0000000..a6dca72
--- /dev/null
+++ b/dbs-reader/src/wallets.rs
@@ -0,0 +1,319 @@
+// Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use crate::*;
+use duniter_core::crypto::keys::ed25519::PublicKey;
+use duniter_core::crypto::keys::PublicKey as _;
+use duniter_core::dbs::{bincode_db, IdtyDbV2, WalletConditionsV2};
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct WalletCursor(WalletScriptV10);
+impl WalletCursor {
+ pub fn from_ref(script: &WalletScriptV10) -> &Self {
+ #[allow(trivial_casts)]
+ unsafe {
+ &*(script as *const WalletScriptV10 as *const WalletCursor)
+ }
+ }
+}
+
+impl Cursor for WalletCursor {}
+
+impl Default for WalletCursor {
+ fn default() -> Self {
+ WalletCursor(WalletScriptV10::single_sig(PublicKey::default()))
+ }
+}
+
+impl std::fmt::Display for WalletCursor {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0.to_string())
+ }
+}
+
+impl FromStr for WalletCursor {
+ type Err = WrongCursor;
+
+ fn from_str(s: &str) -> Result {
+ if let Ok(pubkey) = PublicKey::from_base58(s) {
+ Ok(WalletCursor(WalletScriptV10::single_sig(pubkey)))
+ } else if let Ok(wallet_script) = duniter_core::documents_parser::wallet_script_from_str(s)
+ {
+ Ok(WalletCursor(wallet_script))
+ } else {
+ Err(WrongCursor)
+ }
+ }
+}
+
+impl Ord for WalletCursor {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ use bincode::config::Options as _;
+ let self_bin = bincode_db()
+ .serialize(&self.0)
+ .unwrap_or_else(|_| unreachable!());
+ let other_bin = bincode_db()
+ .serialize(&other.0)
+ .unwrap_or_else(|_| unreachable!());
+ self_bin.cmp(&other_bin)
+ }
+}
+
+impl From for WalletConditionsV2 {
+ fn from(val: WalletCursor) -> Self {
+ WalletConditionsV2(val.0)
+ }
+}
+
+impl PartialOrd for WalletCursor {
+ fn partial_cmp(&self, other: &Self) -> Option {
+ use bincode::config::Options as _;
+ let self_bin = bincode_db()
+ .serialize(&self.0)
+ .unwrap_or_else(|_| unreachable!());
+ let other_bin = bincode_db()
+ .serialize(&other.0)
+ .unwrap_or_else(|_| unreachable!());
+ self_bin.partial_cmp(&other_bin)
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct PublicKeyWithBalance(pub PublicKey, pub SourceAmount);
+impl AsRef for PublicKeyWithBalance {
+ fn as_ref(&self) -> &PubKeyCursor {
+ PubKeyCursor::from_ref(&self.0)
+ }
+}
+
+#[derive(Debug)]
+pub struct ScriptWithBalance(pub WalletScriptV10, pub SourceAmount);
+impl AsRef for ScriptWithBalance {
+ fn as_ref(&self) -> &WalletCursor {
+ WalletCursor::from_ref(&self.0)
+ }
+}
+
+#[derive(Debug)]
+pub struct WalletSingleSigWithIdtyOpt(pub PublicKeyWithBalance, pub Option);
+
+#[derive(Debug)]
+pub struct WalletWithIdtyOpt(pub ScriptWithBalance, pub Option);
+
+impl DbsReaderImpl {
+ pub(super) fn wallets_(
+ &self,
+ exclude_single_sig: bool,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ if let Some(min_balance) = min_balance_opt {
+ if exclude_single_sig {
+ self.wallets_inner(
+ |(k, v)| {
+ if !k.0.is_single_sig() && v.0 >= min_balance {
+ Some(ScriptWithBalance(k.0, v.0))
+ } else {
+ None
+ }
+ },
+ page_info,
+ )
+ } else {
+ self.wallets_inner(
+ |(k, v)| {
+ if v.0 >= min_balance {
+ Some(ScriptWithBalance(k.0, v.0))
+ } else {
+ None
+ }
+ },
+ page_info,
+ )
+ }
+ } else if exclude_single_sig {
+ self.wallets_inner(
+ |(k, v)| {
+ if !k.0.is_single_sig() {
+ Some(ScriptWithBalance(k.0, v.0))
+ } else {
+ None
+ }
+ },
+ page_info,
+ )
+ } else {
+ self.wallets_inner(|(k, v)| Some(ScriptWithBalance(k.0, v.0)), page_info)
+ }
+ }
+
+ pub(super) fn wallets_with_idty_opt_(
+ &self,
+ bc_db: &BcV2DbRo,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ let paged_data = self.wallets_(false, min_balance_opt, page_info)?;
+
+ let mut data = Vec::with_capacity(paged_data.data.len());
+ for script_with_balance in paged_data.data {
+ let idty_opt = if let Some(pubkey) = script_with_balance.0.as_single_sig() {
+ bc_db.identities().get(&PubKeyKeyV2(pubkey))?
+ } else {
+ None
+ };
+
+ data.push(WalletWithIdtyOpt(script_with_balance, idty_opt));
+ }
+
+ Ok(PagedData {
+ data,
+ has_next_page: paged_data.has_next_page,
+ has_previous_page: paged_data.has_previous_page,
+ })
+ }
+
+ pub(super) fn wallets_single_sig_(
+ &self,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ if let Some(min_balance) = min_balance_opt {
+ self.wallets_inner(
+ |(k, v)| {
+ if v.0 >= min_balance {
+ k.0.as_single_sig().map(|pk| PublicKeyWithBalance(pk, v.0))
+ } else {
+ None
+ }
+ },
+ page_info,
+ )
+ } else {
+ self.wallets_inner(
+ |(k, v)| k.0.as_single_sig().map(|pk| PublicKeyWithBalance(pk, v.0)),
+ page_info,
+ )
+ }
+ }
+
+ pub(super) fn wallets_single_sig_with_idty_opt_(
+ &self,
+ bc_db: &BcV2DbRo,
+ min_balance_opt: Option,
+ page_info: PageInfo,
+ ) -> KvResult>> {
+ let paged_data = self.wallets_single_sig_(min_balance_opt, page_info)?;
+
+ let mut data = Vec::with_capacity(paged_data.data.len());
+ for pk_with_balance in paged_data.data {
+ let idty_opt = bc_db.identities().get(&PubKeyKeyV2(pk_with_balance.0))?;
+ data.push(WalletSingleSigWithIdtyOpt(pk_with_balance, idty_opt));
+ }
+
+ Ok(PagedData {
+ data,
+ has_next_page: paged_data.has_next_page,
+ has_previous_page: paged_data.has_previous_page,
+ })
+ }
+
+ fn wallets_inner(
+ &self,
+ filter_map: F,
+ page_info: PageInfo,
+ ) -> KvResult>>
+ where
+ C: Cursor + Into,
+ E: AsRef + std::fmt::Debug + Send + Sync,
+ F: Copy + Fn((WalletConditionsV2, SourceAmountValV2)) -> Option,
+ {
+ let first_cursor_opt = if page_info.not_all() {
+ self.0
+ .balances()
+ .iter(.., |it| it.filter_map_ok(filter_map).next_res())?
+ .map(|element| element.as_ref().to_owned())
+ } else {
+ None
+ };
+ let last_cursor_opt = if page_info.not_all() {
+ self.0
+ .balances()
+ .iter_rev(.., |it| it.filter_map_ok(filter_map).next_res())?
+ .map(|element| element.as_ref().to_owned())
+ } else {
+ None
+ };
+
+ let cursor_opt = page_info.pos.clone();
+ let data = if page_info.order {
+ let first_key = cursor_opt
+ .unwrap_or_else(|| first_cursor_opt.clone().unwrap_or_default())
+ .into();
+ self.0.balances().iter(first_key.., |it| {
+ if let Some(limit) = page_info.limit_opt {
+ it.filter_map_ok(filter_map)
+ .take(limit.get())
+ .collect::>>()
+ } else {
+ it.filter_map_ok(filter_map).collect::>>()
+ }
+ })?
+ } else {
+ let last_key = cursor_opt
+ .unwrap_or_else(|| last_cursor_opt.clone().unwrap_or_default())
+ .into();
+ self.0.balances().iter_rev(..=last_key, |it| {
+ if let Some(limit) = page_info.limit_opt {
+ it.filter_map_ok(filter_map)
+ .take(limit.get())
+ .collect::>>()
+ } else {
+ it.filter_map_ok(filter_map).collect::>>()
+ }
+ })?
+ };
+
+ let page_not_reversed = page_info.order;
+
+ Ok(PagedData {
+ has_next_page: if page_info.order {
+ has_next_page(
+ data.iter()
+ .map(|element| OwnedOrRef::Borrow(element.as_ref())),
+ last_cursor_opt,
+ page_info.clone(),
+ page_not_reversed,
+ )
+ } else {
+ // Server can't efficiently determine hasNextPage in DESC order
+ false
+ },
+ has_previous_page: if page_info.order {
+ // Server can't efficiently determine hasPreviousPage in ASC order
+ false
+ } else {
+ has_previous_page(
+ data.iter()
+ .map(|element| OwnedOrRef::Borrow(element.as_ref())),
+ first_cursor_opt,
+ page_info,
+ page_not_reversed,
+ )
+ },
+ data,
+ })
+ }
+}
diff --git a/gql/src/entities.rs b/gql/src/entities.rs
index a7f5102..b2c93db 100644
--- a/gql/src/entities.rs
+++ b/gql/src/entities.rs
@@ -19,6 +19,7 @@ pub mod network;
pub mod tx_gva;
pub mod ud_gva;
pub mod utxos_gva;
+pub mod wallet_gva;
use crate::*;
@@ -27,11 +28,19 @@ pub(crate) struct AggregateSum {
pub(crate) aggregate: Sum,
}
-#[derive(Default, async_graphql::SimpleObject)]
+#[derive(Clone, Copy, Debug, Default, async_graphql::SimpleObject)]
pub(crate) struct AmountWithBase {
pub(crate) amount: i32,
pub(crate) base: i32,
}
+impl From for AmountWithBase {
+ fn from(sa: SourceAmount) -> Self {
+ Self {
+ amount: sa.amount() as i32,
+ base: sa.base() as i32,
+ }
+ }
+}
#[derive(async_graphql::SimpleObject)]
pub(crate) struct EdgeTx {
diff --git a/gql/src/entities/idty_gva.rs b/gql/src/entities/idty_gva.rs
index ee77b0e..8729895 100644
--- a/gql/src/entities/idty_gva.rs
+++ b/gql/src/entities/idty_gva.rs
@@ -13,7 +13,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-#[derive(async_graphql::SimpleObject)]
+#[derive(Clone, Debug, async_graphql::SimpleObject)]
pub(crate) struct Identity {
pub is_member: bool,
pub username: String,
diff --git a/gql/src/entities/wallet_gva.rs b/gql/src/entities/wallet_gva.rs
new file mode 100644
index 0000000..dfab890
--- /dev/null
+++ b/gql/src/entities/wallet_gva.rs
@@ -0,0 +1,41 @@
+// Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use crate::*;
+
+#[derive(Clone, Copy, async_graphql::Enum, Eq, PartialEq)]
+pub(crate) enum WalletTypeFilter {
+ /// All wallets
+ All,
+ /// Exclude wallets scripts with single SIG condition
+ OnlyComplex,
+ /// Only wallets scripts with single SIG condition
+ OnlySimple,
+}
+impl Default for WalletTypeFilter {
+ fn default() -> WalletTypeFilter {
+ WalletTypeFilter::OnlySimple
+ }
+}
+
+#[derive(Clone, Debug, async_graphql::SimpleObject)]
+pub(crate) struct Wallet {
+ /// Wallet script or public key
+ pub(crate) script: String,
+ /// Wallet balance
+ pub(crate) balance: AmountWithBase,
+ /// Optional identity attached to this wallet
+ pub(crate) idty: Option,
+}
diff --git a/gql/src/lib.rs b/gql/src/lib.rs
index e801b81..1d91438 100644
--- a/gql/src/lib.rs
+++ b/gql/src/lib.rs
@@ -41,6 +41,7 @@ use crate::entities::{
tx_gva::{PendingTxGva, WrittenTxGva},
ud_gva::{CurrentUdGva, RevalUdGva, UdGva},
utxos_gva::UtxosGva,
+ wallet_gva::{Wallet, WalletTypeFilter},
AggregateSum, AmountWithBase, EdgeTx, RawTxOrChanges, Sum, TxDirection, TxsHistoryMempool,
UtxoGva, UtxoTimedGva,
};
diff --git a/gql/src/queries.rs b/gql/src/queries.rs
index ad733e3..1026447 100644
--- a/gql/src/queries.rs
+++ b/gql/src/queries.rs
@@ -24,6 +24,7 @@ pub mod network;
pub mod txs_history;
pub mod uds;
pub mod utxos_of_script;
+pub mod wallets;
use crate::*;
@@ -42,6 +43,7 @@ pub struct QueryRoot(
queries::txs_history::TxsHistoryMempoolQuery,
queries::uds::UdsQuery,
queries::utxos_of_script::UtxosQuery,
+ queries::wallets::WalletsQuery,
);
#[derive(Default, async_graphql::SimpleObject)]
diff --git a/gql/src/queries/wallets.rs b/gql/src/queries/wallets.rs
new file mode 100644
index 0000000..699a085
--- /dev/null
+++ b/gql/src/queries/wallets.rs
@@ -0,0 +1,172 @@
+// Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use crate::*;
+use async_graphql::connection::*;
+use duniter_gva_dbs_reader::{
+ wallets::{WalletSingleSigWithIdtyOpt, WalletWithIdtyOpt},
+ PagedData,
+};
+
+#[derive(Default)]
+pub(crate) struct WalletsQuery;
+#[async_graphql::Object]
+impl WalletsQuery {
+ /// Universal dividends issued by a public key
+ #[allow(clippy::clippy::too_many_arguments)]
+ async fn wallets(
+ &self,
+ ctx: &async_graphql::Context<'_>,
+ #[graphql(desc = "minimal balance")] min_balance: Option,
+ #[graphql(desc = "pagination", default)] pagination: Pagination,
+ #[graphql(desc = "Wallet type filter", default)] wallet_type_filter: WalletTypeFilter,
+ ) -> async_graphql::Result> {
+ let QueryContext { is_whitelisted } = ctx.data::()?;
+
+ let data = ctx.data::()?;
+ let dbs_reader = data.dbs_reader();
+
+ let current_base =
+ if let Some(current_ud) = data.cm_accessor.get_current_meta(|cm| cm.current_ud).await {
+ current_ud.base()
+ } else {
+ 0
+ };
+ let min_balance_opt = min_balance.map(|amount| SourceAmount::new(amount, current_base));
+
+ let PagedData {
+ data,
+ has_next_page,
+ has_previous_page,
+ }: PagedData> = match wallet_type_filter {
+ WalletTypeFilter::OnlyComplex => {
+ let pagination = Pagination::convert_to_page_info(pagination, *is_whitelisted)?;
+ data.dbs_pool
+ .execute(move |_| dbs_reader.wallets(true, min_balance_opt, pagination))
+ .await??
+ .map(|data| {
+ data.into_iter()
+ .map(|script_with_sa| Wallet {
+ script: script_with_sa.0.to_string(),
+ balance: AmountWithBase::from(script_with_sa.1),
+ idty: None,
+ })
+ .collect()
+ })
+ }
+ WalletTypeFilter::OnlySimple => {
+ let pagination = Pagination::convert_to_page_info(pagination, *is_whitelisted)?;
+ if ctx
+ .look_ahead()
+ .field("edges")
+ .field("node")
+ .field("idty")
+ .exists()
+ {
+ data.dbs_pool
+ .execute(move |shared_dbs| {
+ dbs_reader.wallets_single_sig_with_idty_opt(
+ &shared_dbs.bc_db_ro,
+ min_balance_opt,
+ pagination,
+ )
+ })
+ .await??
+ .map(|data| {
+ data.into_iter()
+ .map(|WalletSingleSigWithIdtyOpt(pk_with_sa, idty_opt)| Wallet {
+ script: pk_with_sa.0.to_string(),
+ balance: AmountWithBase::from(pk_with_sa.1),
+ idty: idty_opt.map(|idty_db| Identity {
+ is_member: idty_db.is_member,
+ username: idty_db.username,
+ }),
+ })
+ .collect()
+ })
+ } else {
+ data.dbs_pool
+ .execute(move |_| {
+ dbs_reader.wallets_single_sig(min_balance_opt, pagination)
+ })
+ .await??
+ .map(|data| {
+ data.into_iter()
+ .map(|pk_with_sa| Wallet {
+ script: pk_with_sa.0.to_string(),
+ balance: AmountWithBase::from(pk_with_sa.1),
+ idty: None,
+ })
+ .collect()
+ })
+ }
+ }
+ WalletTypeFilter::All => {
+ let pagination = Pagination::convert_to_page_info(pagination, *is_whitelisted)?;
+ if ctx
+ .look_ahead()
+ .field("edges")
+ .field("node")
+ .field("idty")
+ .exists()
+ {
+ data.dbs_pool
+ .execute(move |shared_dbs| {
+ dbs_reader.wallets_with_idty_opt(
+ &shared_dbs.bc_db_ro,
+ min_balance_opt,
+ pagination,
+ )
+ })
+ .await??
+ .map(|data| {
+ data.into_iter()
+ .map(|WalletWithIdtyOpt(script_with_sa, idty_opt)| Wallet {
+ script: script_with_sa.0.to_string(),
+ balance: AmountWithBase::from(script_with_sa.1),
+ idty: idty_opt.map(|idty_db| Identity {
+ is_member: idty_db.is_member,
+ username: idty_db.username,
+ }),
+ })
+ .collect()
+ })
+ } else {
+ data.dbs_pool
+ .execute(move |_| dbs_reader.wallets(false, min_balance_opt, pagination))
+ .await??
+ .map(|data| {
+ data.into_iter()
+ .map(|script_with_sa| Wallet {
+ script: script_with_sa.0.to_string(),
+ balance: AmountWithBase::from(script_with_sa.1),
+ idty: None,
+ })
+ .collect()
+ })
+ }
+ }
+ };
+
+ let mut conn = Connection::new(has_previous_page, has_next_page);
+
+ conn.append(
+ data.into_iter()
+ .map(|wallet| Edge::new(wallet.script.clone(), wallet)),
+ );
+
+ Ok(conn)
+ }
+}