Merge branch 'tauri-wallet' into tauri-wallet-frontend
rust updates
This commit is contained in:
Generated
+3
@@ -3612,9 +3612,11 @@ name = "nym_wallet"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bip39",
|
||||
"coconut-interface",
|
||||
"config",
|
||||
"cosmos_sdk",
|
||||
"cosmwasm-std",
|
||||
"credentials",
|
||||
"dirs",
|
||||
"mixnet-contract",
|
||||
"serde",
|
||||
@@ -3625,6 +3627,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"ts-rs",
|
||||
"url",
|
||||
"validator-client",
|
||||
]
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::nymd::GasPrice;
|
||||
use cosmos_sdk::tx::{Fee, Gas};
|
||||
use cosmos_sdk::Coin;
|
||||
use cosmwasm_std::Uint128;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||
pub enum Operation {
|
||||
@@ -37,6 +38,27 @@ pub(crate) fn calculate_fee(gas_price: &GasPrice, gas_limit: Gas) -> Coin {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Operation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Operation::Upload => f.write_str("Upload"),
|
||||
Operation::Init => f.write_str("Init"),
|
||||
Operation::Migrate => f.write_str("Migrate"),
|
||||
Operation::ChangeAdmin => f.write_str("ChangeAdmin"),
|
||||
Operation::Send => f.write_str("Send"),
|
||||
Operation::BondMixnode => f.write_str("BondMixnode"),
|
||||
Operation::UnbondMixnode => f.write_str("UnbondMixnode"),
|
||||
Operation::DelegateToMixnode => f.write_str("DelegateToMixnode"),
|
||||
Operation::UndelegateFromMixnode => f.write_str("UndelegateFromMixnode"),
|
||||
Operation::BondGateway => f.write_str("BondGateway"),
|
||||
Operation::UnbondGateway => f.write_str("UnbondGateway"),
|
||||
Operation::DelegateToGateway => f.write_str("DelegateToGateway"),
|
||||
Operation::UndelegateFromGateway => f.write_str("UndelegateFromGateway"),
|
||||
Operation::UpdateStateParams => f.write_str("UpdateStateParams"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
// TODO: some value tweaking
|
||||
pub(crate) fn default_gas_limit(&self) -> Gas {
|
||||
|
||||
@@ -122,6 +122,14 @@ impl<C> NymdClient<C> {
|
||||
self.custom_gas_limits.insert(operation, limit);
|
||||
}
|
||||
|
||||
pub fn get_gas_price(&self) -> GasPrice {
|
||||
self.gas_price.clone()
|
||||
}
|
||||
|
||||
pub fn get_custom_gas_limits(&self) -> HashMap<Operation, Gas> {
|
||||
self.custom_gas_limits.clone()
|
||||
}
|
||||
|
||||
pub fn contract_address(&self) -> Result<&AccountId, NymdError> {
|
||||
self.contract_address
|
||||
.as_ref()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ValidatorDetails {
|
||||
// it is assumed those values are always valid since they're being provided in our defaults file
|
||||
pub nymd_url: String,
|
||||
|
||||
@@ -25,6 +25,7 @@ bip39 = "1.0"
|
||||
thiserror = "1.0"
|
||||
tendermint-rpc = "0.21.0"
|
||||
ts-rs = "3.0"
|
||||
url = "2.0"
|
||||
|
||||
cosmos_sdk = { git = "https://github.com/cosmos/cosmos-rust/", rev = "ba012bd820240d3df2d9a0ab1deabe4ecd9a2f30", features = [
|
||||
"rpc",
|
||||
@@ -38,6 +39,8 @@ validator-client = { path = "../../common/client-libs/validator-client", feature
|
||||
] }
|
||||
mixnet-contract = { path = "../../common/mixnet-contract" }
|
||||
config = { path = "../../common/config" }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
|
||||
[features]
|
||||
default = ["custom-protocol"]
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use coconut_interface::{
|
||||
self, Credential, Signature, Theta, VerificationKey,
|
||||
};
|
||||
use crate::state::State;
|
||||
use credentials::{obtain_aggregate_signature, obtain_aggregate_verification_key};
|
||||
use url::Url;
|
||||
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn randomise_credential(
|
||||
idx: usize,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Vec<Signature>, String> {
|
||||
let mut state = state.write().await;
|
||||
let signature = state.signatures.remove(idx);
|
||||
let new = signature.randomise(state.params()?);
|
||||
state.signatures.insert(idx, new);
|
||||
Ok(state.signatures.clone())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_credential(
|
||||
idx: usize,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Vec<Signature>, String> {
|
||||
let mut state = state.write().await;
|
||||
state.signatures.remove(idx);
|
||||
Ok(state.signatures.clone())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_credentials(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Vec<Signature>, String> {
|
||||
let state = state.read().await;
|
||||
Ok(state.signatures.clone())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn verify_credential(
|
||||
idx: usize,
|
||||
validator_urls: Vec<String>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<bool, String> {
|
||||
// the API needs to be improved but at least it should compile (in theory)
|
||||
let verification_key =
|
||||
get_aggregated_verification_key(validator_urls.clone(), state.clone()).await?;
|
||||
let theta = prove_credential(idx, validator_urls, state.clone()).await?;
|
||||
|
||||
let state = state.read().await;
|
||||
|
||||
let credential = Credential::new(
|
||||
state.n_attributes(),
|
||||
theta,
|
||||
&state.public_attributes(),
|
||||
state
|
||||
.signatures
|
||||
.get(idx)
|
||||
.ok_or("Got invalid signature idx")?,
|
||||
);
|
||||
|
||||
Ok(credential.verify(&verification_key).await)
|
||||
}
|
||||
|
||||
async fn prove_credential(
|
||||
idx: usize,
|
||||
validator_urls: Vec<String>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Theta, String> {
|
||||
let verification_key = get_aggregated_verification_key(validator_urls, state.clone()).await?;
|
||||
let state = state.read().await;
|
||||
|
||||
if let Some(signature) = state.signatures.get(idx) {
|
||||
match coconut_interface::prove_credential(
|
||||
state.params()?,
|
||||
&verification_key,
|
||||
signature,
|
||||
&state.private_attributes(),
|
||||
) {
|
||||
Ok(theta) => Ok(theta),
|
||||
Err(e) => Err(format!("{}", e)),
|
||||
}
|
||||
} else {
|
||||
Err("Got invalid Signature idx".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_aggregated_verification_key(
|
||||
validator_urls: Vec<String>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<VerificationKey, String> {
|
||||
if let Some(verification_key) = &state.read().await.aggregated_verification_key {
|
||||
return Ok(verification_key.clone());
|
||||
}
|
||||
|
||||
let parsed_urls = parse_url_validators(&validator_urls)?;
|
||||
let key = obtain_aggregate_verification_key(&parsed_urls)
|
||||
.await
|
||||
.map_err(|err| format!("failed to obtain aggregate verification key - {:?}", err))?;
|
||||
|
||||
state
|
||||
.write()
|
||||
.await
|
||||
.aggregated_verification_key
|
||||
.replace(key.clone());
|
||||
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
fn parse_url_validators(raw: &[String]) -> Result<Vec<Url>, String> {
|
||||
let mut parsed_urls = Vec::with_capacity(raw.len());
|
||||
for url in raw {
|
||||
let parsed_url: Url = url
|
||||
.parse()
|
||||
.map_err(|err| format!("one of validator urls is malformed - {}", err))?;
|
||||
parsed_urls.push(parsed_url)
|
||||
}
|
||||
Ok(parsed_urls)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_credential(
|
||||
validator_urls: Vec<String>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Vec<Signature>, String> {
|
||||
let guard = state.read().await;
|
||||
let parsed_urls = parse_url_validators(&validator_urls)?;
|
||||
|
||||
let signature = obtain_aggregate_signature(
|
||||
guard.params()?,
|
||||
&guard.public_attributes(),
|
||||
&guard.private_attributes(),
|
||||
&parsed_urls,
|
||||
)
|
||||
.await
|
||||
.map_err(|err| format!("failed to obtain aggregate signature - {:?}", err))?;
|
||||
|
||||
let mut state = state.write().await;
|
||||
state.signatures.push(signature);
|
||||
Ok(state.signatures.clone())
|
||||
}
|
||||
@@ -14,13 +14,13 @@ use template::config_template;
|
||||
|
||||
use crate::error::BackendError;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
base: Base,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Base {
|
||||
validators: Vec<ValidatorDetails>,
|
||||
|
||||
+160
-140
@@ -12,22 +12,30 @@ use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
use error::BackendError;
|
||||
use mixnet_contract::{Gateway, MixNode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tendermint_rpc::endpoint::broadcast::tx_commit::Response;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use ts_rs::{export, TS};
|
||||
use validator_client::nymd::{NymdClient, SigningNymdClient};
|
||||
|
||||
mod config;
|
||||
mod error;
|
||||
// mod nymd_client;
|
||||
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use ts_rs::{export, TS};
|
||||
use validator_client::nymd::GasPrice;
|
||||
use validator_client::nymd::{NymdClient, SigningNymdClient};
|
||||
|
||||
mod coconut;
|
||||
mod config;
|
||||
mod error;
|
||||
mod state;
|
||||
|
||||
use crate::coconut::{
|
||||
delete_credential, get_credential, list_credentials, randomise_credential, verify_credential,
|
||||
};
|
||||
use crate::state::State;
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! format_err {
|
||||
($e:expr) => {
|
||||
format!("line {}: {}", line!(), $e)
|
||||
@@ -71,6 +79,36 @@ impl FromStr for Denom {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, TS)]
|
||||
struct TauriTxResult {
|
||||
code: u32,
|
||||
gas_wanted: u64,
|
||||
gas_used: u64,
|
||||
block_height: u64,
|
||||
details: TransactionDetails,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, TS)]
|
||||
struct TransactionDetails {
|
||||
from_address: String,
|
||||
to_address: String,
|
||||
amount: Coin
|
||||
}
|
||||
|
||||
|
||||
impl TauriTxResult {
|
||||
fn new(t: Response, details: TransactionDetails) -> TauriTxResult {
|
||||
TauriTxResult {
|
||||
code: t.check_tx.code.value(),
|
||||
gas_wanted: t.check_tx.gas_wanted.value(),
|
||||
gas_used: t.check_tx.gas_used.value(),
|
||||
block_height: t.height.value(),
|
||||
details
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Proxy types to allow TS generation
|
||||
#[derive(TS, Serialize, Deserialize, Clone)]
|
||||
struct Coin {
|
||||
@@ -78,6 +116,15 @@ struct Coin {
|
||||
denom: String,
|
||||
}
|
||||
|
||||
impl From<GasPrice> for Coin {
|
||||
fn from(g: GasPrice) -> Coin {
|
||||
Coin {
|
||||
amount: g.amount.to_string(),
|
||||
denom: g.denom.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Coin {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&format!("{} {}", self.amount, self.denom))
|
||||
@@ -153,12 +200,6 @@ impl From<CosmosCoin> for Coin {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct State {
|
||||
config: Config,
|
||||
signing_client: Option<NymdClient<SigningNymdClient>>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn major_to_minor(amount: String) -> Result<Coin, String> {
|
||||
let coin = Coin {
|
||||
@@ -189,7 +230,7 @@ async fn connect_with_mnemonic(
|
||||
let client;
|
||||
{
|
||||
let r_state = state.read().await;
|
||||
client = _connect_with_mnemonic(mnemonic, &r_state.config);
|
||||
client = _connect_with_mnemonic(mnemonic, &r_state.config());
|
||||
}
|
||||
|
||||
let mut ret = HashMap::new();
|
||||
@@ -209,7 +250,7 @@ async fn connect_with_mnemonic(
|
||||
},
|
||||
);
|
||||
let mut w_state = state.write().await;
|
||||
w_state.signing_client = Some(client);
|
||||
w_state.set_client(client);
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
@@ -217,73 +258,53 @@ async fn connect_with_mnemonic(
|
||||
#[tauri::command]
|
||||
async fn get_balance(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<Balance, String> {
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.get_balance(client.address()).await {
|
||||
Ok(Some(coin)) => {
|
||||
let coin = Coin {
|
||||
amount: coin.amount.to_string(),
|
||||
denom: coin.denom.to_string(),
|
||||
};
|
||||
Ok(Balance {
|
||||
coin: coin.clone(),
|
||||
printable_balance: coin.to_major().to_string(),
|
||||
})
|
||||
}
|
||||
Ok(None) => Err(format!(
|
||||
"No balance available for address {}",
|
||||
client.address()
|
||||
)),
|
||||
Err(e) => Err(BackendError::from(e).to_string()),
|
||||
let client = r_state.client()?;
|
||||
match client.get_balance(client.address()).await {
|
||||
Ok(Some(coin)) => {
|
||||
let coin = Coin {
|
||||
amount: coin.amount.to_string(),
|
||||
denom: coin.denom.to_string(),
|
||||
};
|
||||
Ok(Balance {
|
||||
coin: coin.clone(),
|
||||
printable_balance: coin.to_major().to_string(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
Ok(None) => Err(format!(
|
||||
"No balance available for address {}",
|
||||
client.address()
|
||||
)),
|
||||
Err(e) => Err(BackendError::from(e).to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn owns_mixnode(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<bool, String> {
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.owns_mixnode(client.address()).await {
|
||||
Ok(o) => Ok(o),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.owns_mixnode(client.address()).await {
|
||||
Ok(o) => Ok(o),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn owns_gateway(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<bool, String> {
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.owns_gateway(client.address()).await {
|
||||
Ok(o) => Ok(o),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.owns_gateway(client.address()).await {
|
||||
Ok(o) => Ok(o),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn unbond_mixnode(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<(), String> {
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.unbond_mixnode().await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.unbond_mixnode().await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,15 +319,10 @@ async fn bond_mixnode(
|
||||
Ok(b) => b,
|
||||
Err(e) => return Err(format_err!(e)),
|
||||
};
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.bond_mixnode(mixnode, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.bond_mixnode(mixnode, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,15 +337,10 @@ async fn delegate_to_mixnode(
|
||||
Ok(b) => b,
|
||||
Err(e) => return Err(format_err!(e)),
|
||||
};
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.delegate_to_mixnode(identity, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.delegate_to_mixnode(identity, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,15 +350,10 @@ async fn undelegate_from_mixnode(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<(), String> {
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.remove_mixnode_delegation(identity).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.remove_mixnode_delegation(identity).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,15 +368,10 @@ async fn delegate_to_gateway(
|
||||
Ok(b) => b,
|
||||
Err(e) => return Err(format_err!(e)),
|
||||
};
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.delegate_to_gateway(identity, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.delegate_to_gateway(identity, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,15 +381,10 @@ async fn undelegate_from_gateway(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<(), String> {
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.remove_gateway_delegation(identity).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.remove_gateway_delegation(identity).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,56 +399,71 @@ async fn bond_gateway(
|
||||
Ok(b) => b,
|
||||
Err(e) => return Err(format_err!(e)),
|
||||
};
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.bond_gateway(gateway, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.bond_gateway(gateway, bond).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn unbond_gateway(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<(), String> {
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.unbond_gateway().await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.unbond_gateway().await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn send(address: &str, amount: Coin, memo: String, state: tauri::State<'_, Arc<RwLock<State>>>,) -> Result<(), String> {
|
||||
async fn send(
|
||||
address: &str,
|
||||
amount: Coin,
|
||||
memo: String,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TauriTxResult, String> {
|
||||
let address = match AccountId::from_str(address) {
|
||||
Ok(addy) => addy,
|
||||
Err(e) => return Err(format_err!(e))
|
||||
Err(e) => return Err(format_err!(e)),
|
||||
};
|
||||
let amount: CosmosCoin = match amount.try_into() {
|
||||
let cosmos_amount: CosmosCoin = match amount.clone().try_into() {
|
||||
Ok(b) => b,
|
||||
Err(e) => return Err(format_err!(e)),
|
||||
};
|
||||
let r_state = state.read().await;
|
||||
if let Some(client) = &r_state.signing_client {
|
||||
match client.send(&address, vec!(amount), memo).await {
|
||||
Ok(_result) => Ok(()),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
} else {
|
||||
Err(String::from(
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize",
|
||||
))
|
||||
let client = r_state.client()?;
|
||||
match client.send(&address, vec![cosmos_amount], memo).await {
|
||||
Ok(result) => Ok(TauriTxResult::new(result, TransactionDetails {
|
||||
from_address: client.address().to_string(),
|
||||
to_address: address.to_string(),
|
||||
amount: amount.into()
|
||||
})),
|
||||
Err(e) => Err(format_err!(e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_gas_price(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<Coin, String> {
|
||||
let r_state = state.read().await;
|
||||
let client = r_state.client()?;
|
||||
let coin = client.get_gas_price().into();
|
||||
Ok(coin)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_gas_limits(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<HashMap<String, u64>, String> {
|
||||
let r_state = state.read().await;
|
||||
let client = r_state.client()?;
|
||||
let mut limits = HashMap::new();
|
||||
for (k, v) in client.get_custom_gas_limits() {
|
||||
limits.insert(k.to_string(), v.value());
|
||||
}
|
||||
Ok(limits)
|
||||
}
|
||||
|
||||
fn _connect_with_mnemonic(mnemonic: Mnemonic, config: &Config) -> NymdClient<SigningNymdClient> {
|
||||
match NymdClient::connect_with_mnemonic(
|
||||
config.get_nymd_validator_url().unwrap(),
|
||||
@@ -482,7 +493,14 @@ fn main() {
|
||||
undelegate_from_mixnode,
|
||||
delegate_to_gateway,
|
||||
undelegate_from_gateway,
|
||||
send
|
||||
send,
|
||||
get_gas_price,
|
||||
get_gas_limits,
|
||||
get_credential,
|
||||
randomise_credential,
|
||||
delete_credential,
|
||||
list_credentials,
|
||||
verify_credential
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
@@ -492,5 +510,7 @@ export! {
|
||||
MixNode => "../src/types/rust/mixnode.ts",
|
||||
Coin => "../src/types/rust/coin.ts",
|
||||
Balance => "../src/types/rust/balance.ts",
|
||||
Gateway => "../src/types/rust/gateway.ts"
|
||||
Gateway => "../src/types/rust/gateway.ts",
|
||||
TauriTxResult => "../src/types/rust/tauritxresult.ts",
|
||||
TransactionDetails => "../src/types/rust/transactiondetails.ts"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
use crate::config::Config;
|
||||
use crate::format_err;
|
||||
use coconut_interface::{
|
||||
self, Attribute, Parameters, Signature, VerificationKey,
|
||||
};
|
||||
use validator_client::nymd::{NymdClient, SigningNymdClient};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct State {
|
||||
config: Config,
|
||||
signing_client: Option<NymdClient<SigningNymdClient>>,
|
||||
// Coconut stuff
|
||||
pub signatures: Vec<Signature>,
|
||||
n_attributes: u32,
|
||||
params: Option<Parameters>,
|
||||
public_attributes: Vec<Attribute>,
|
||||
private_attributes: Vec<Attribute>,
|
||||
pub aggregated_verification_key: Option<VerificationKey>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn client(&self) -> Result<&NymdClient<SigningNymdClient>, String> {
|
||||
self.signing_client.as_ref().ok_or_else(|| {
|
||||
"Client has not been initialized yet, connect with mnemonic to initialize".to_string()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn config(&self) -> Config {
|
||||
self.config.clone()
|
||||
}
|
||||
|
||||
pub fn set_client(&mut self, signing_client: NymdClient<SigningNymdClient>) {
|
||||
self.signing_client = Some(signing_client)
|
||||
}
|
||||
|
||||
pub fn params(&self) -> Result<&Parameters, String> {
|
||||
self
|
||||
.params
|
||||
.as_ref()
|
||||
.ok_or_else(|| format_err!("Parameters are not set!"))
|
||||
}
|
||||
|
||||
pub fn private_attributes(&self) -> Vec<Attribute> {
|
||||
self.private_attributes.clone()
|
||||
}
|
||||
|
||||
pub fn public_attributes(&self) -> Vec<Attribute> {
|
||||
self.public_attributes.clone()
|
||||
}
|
||||
|
||||
pub fn n_attributes(&self) -> u32 {
|
||||
self.n_attributes
|
||||
}
|
||||
|
||||
}
|
||||
@@ -136,6 +136,22 @@ export const ApiList = () => {
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<DocEntry
|
||||
function={{
|
||||
name: "get_gas_price",
|
||||
args: [],
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<DocEntry
|
||||
function={{
|
||||
name: "get_gas_limits",
|
||||
args: [],
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { TransactionDetails } from "./transactiondetails";
|
||||
|
||||
export interface TauriTxResult {
|
||||
code: number;
|
||||
gas_wanted: number;
|
||||
gas_used: number;
|
||||
block_height: number;
|
||||
details: TransactionDetails;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Coin } from "./coin";
|
||||
|
||||
export interface TransactionDetails {
|
||||
from_address: string;
|
||||
to_address: string;
|
||||
amount: Coin;
|
||||
}
|
||||
Reference in New Issue
Block a user