Admin functions, reorganize code

This commit is contained in:
Drazen Urch
2021-09-17 10:43:26 +02:00
committed by fmtabbara
parent 052c7188ec
commit 085538582b
12 changed files with 519 additions and 434 deletions
+1 -1
View File
@@ -212,7 +212,7 @@ impl From<CosmWasmCoin> for Coin {
#[cfg(test)]
mod test {
use crate::{Coin, Denom};
use crate::coin::{Coin, Denom};
use cosmrs::Coin as CosmosCoin;
use cosmrs::Decimal;
use cosmrs::Denom as CosmosDenom;
+17 -353
View File
@@ -3,30 +3,30 @@
windows_subsystem = "windows"
)]
use bip39::{Language, Mnemonic};
use cosmwasm_std::Coin as CosmWasmCoin;
use error::BackendError;
use mixnet_contract::{Gateway, MixNode};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::convert::TryInto;
use std::str::FromStr;
use std::sync::Arc;
use tendermint_rpc::endpoint::broadcast::tx_commit::Response;
use tokio::sync::RwLock;
use ts_rs::{export, TS};
use ts_rs::export;
use validator_client::nymd::fee_helpers::Operation;
use validator_client::nymd::{AccountId, CosmosCoin, NymdClient, SigningNymdClient};
mod coin;
mod config;
mod error;
mod operations;
mod state;
mod utils;
use crate::operations::account::*;
use crate::operations::admin::*;
use crate::operations::bond::*;
use crate::operations::delegate::*;
use crate::operations::send::*;
use crate::utils::*;
use crate::state::State;
#[cfg(test)]
use crate::coin::{Coin, Denom};
use crate::config::Config;
#[macro_export]
macro_rules! format_err {
@@ -35,346 +35,6 @@ macro_rules! format_err {
};
}
#[derive(TS, Serialize, Deserialize)]
struct DelegationResult {
source_address: String,
target_address: String,
amount: Option<Coin>,
}
#[derive(TS, Serialize, Deserialize)]
struct Balance {
coin: Coin,
printable_balance: String,
}
#[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,
}
}
}
// TODO these should be more explicit
#[tauri::command]
fn major_to_minor(amount: &str) -> Result<Coin, String> {
let coin = Coin::new(amount, &Denom::Major);
Ok(coin.to_minor())
}
#[tauri::command]
fn minor_to_major(amount: &str) -> Result<Coin, String> {
let coin = Coin::new(amount, &Denom::Minor);
Ok(coin.to_major())
}
#[tauri::command]
async fn connect_with_mnemonic(
mnemonic: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<HashMap<&str, String>, String> {
let mnemonic = match Mnemonic::from_str(&mnemonic) {
Ok(mnemonic) => mnemonic,
Err(e) => return Err(BackendError::from(e).to_string()),
};
let client;
{
let r_state = state.read().await;
client = _connect_with_mnemonic(mnemonic, &r_state.config());
}
let mut ret = HashMap::new();
ret.insert(
"contract_address",
match client.contract_address() {
Ok(address) => address.to_string(),
Err(e) => format_err!(e),
},
);
ret.insert("client_address", client.address().to_string());
ret.insert(
"denom",
match client.denom() {
Ok(denom) => denom.to_string(),
Err(e) => format_err!(e),
},
);
let mut w_state = state.write().await;
w_state.set_client(client);
Ok(ret)
}
#[tauri::command]
async fn get_balance(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<Balance, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.get_balance(client.address()).await {
Ok(Some(coin)) => {
let coin = Coin::new(
&coin.amount.to_string(),
&Denom::from_str(&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()),
}
}
#[tauri::command]
async fn owns_mixnode(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<bool, String> {
let r_state = state.read().await;
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;
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;
let client = r_state.client()?;
match client.unbond_mixnode().await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
async fn bond_mixnode(
mixnode: MixNode,
bond: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match bond.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.bond_mixnode(mixnode, bond).await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
async fn delegate_to_mixnode(
identity: &str,
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match amount.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.delegate_to_mixnode(identity, &bond).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: Some(bond.into()),
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
async fn undelegate_from_mixnode(
identity: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.remove_mixnode_delegation(identity).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: None,
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
async fn delegate_to_gateway(
identity: &str,
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match amount.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.delegate_to_gateway(identity, &bond).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: Some(bond.into()),
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
async fn undelegate_from_gateway(
identity: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.remove_gateway_delegation(identity).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: None,
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
async fn bond_gateway(
gateway: Gateway,
bond: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match bond.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
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;
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<TauriTxResult, String> {
let address = match AccountId::from_str(address) {
Ok(addy) => addy,
Err(e) => return Err(format_err!(e)),
};
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;
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,
},
)),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
async fn get_fee(
operation: Operation,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, String> {
let r_state = state.read().await;
let client = r_state.client()?;
let fee = client.get_fee(operation);
let mut coin = Coin::new("0", &Denom::Major);
for f in fee.amount {
coin = coin + f.into();
}
Ok(coin)
}
#[tauri::command]
async fn create_new_account(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<HashMap<&str, String>, String> {
let mnemonic = random_mnemonic();
let mut client = connect_with_mnemonic(mnemonic.to_string(), state).await?;
client.insert("mnemonic", mnemonic.to_string());
Ok(client)
}
fn random_mnemonic() -> Mnemonic {
let mut rng = rand::thread_rng();
Mnemonic::generate_in_with(&mut rng, Language::English, 24).unwrap()
}
fn _connect_with_mnemonic(mnemonic: Mnemonic, config: &Config) -> NymdClient<SigningNymdClient> {
match NymdClient::connect_with_mnemonic(
config.get_nymd_validator_url().unwrap(),
Some(AccountId::from_str(&config.get_mixnet_contract_address()).unwrap()),
mnemonic,
) {
Ok(client) => client,
Err(e) => panic!("{}", e),
}
}
fn main() {
tauri::Builder::default()
.manage(Arc::new(RwLock::new(State::default())))
@@ -395,7 +55,9 @@ fn main() {
undelegate_from_gateway,
send,
create_new_account,
get_fee
get_fee,
get_state_params,
update_state_params
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
@@ -410,5 +72,7 @@ export! {
TransactionDetails => "../src/types/rust/transactiondetails.ts",
Operation => "../src/types/rust/operation.ts",
Denom => "../src/types/rust/denom.ts",
DelegationResult => "../src/types/rust/delegationresult.ts"
DelegationResult => "../src/types/rust/delegationresult.ts",
Account => "../src/types/rust/account.ts",
TauriStateParams => "../src/types/rust/stateparams.ts"
}
-80
View File
@@ -1,80 +0,0 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::Config;
use config::defaults::DEFAULT_VALIDATOR_API_PORT;
use mixnet_contract::{GatewayBond, MixNodeBond};
use std::sync::Arc;
use tokio::sync::RwLock;
use validator_client::nymd::{CosmWasmClient, QueryNymdClient, SigningNymdClient, NymdClient};
use validator_client::ValidatorClientError;
#[derive(Clone)]
pub(crate) struct Client<C>(Arc<RwLock<validator_client::Client<C>>>);
impl Client<QueryNymdClient> {
pub(crate) fn new_query(config: &Config) -> Self {
// the api address is irrelevant here as **WE ARE THE API**
let api_url = format!("http://localhost:{}", DEFAULT_VALIDATOR_API_PORT)
.parse()
.unwrap();
let nymd_url = config.get_nymd_validator_url();
let mixnet_contract = config
.get_mixnet_contract_address()
.parse()
.expect("the mixnet contract address is invalid!");
let client_config = validator_client::Config::new(nymd_url, api_url, Some(mixnet_contract));
let inner =
validator_client::Client::new_query(client_config).expect("Failed to connect to nymd!");
Client(Arc::new(RwLock::new(inner)))
}
}
impl Client<SigningNymdClient> {
pub(crate) fn new_signing(config: &Config) -> Self {
// the api address is irrelevant here as **WE ARE THE API**
let api_url = format!("http://localhost:{}", DEFAULT_VALIDATOR_API_PORT)
.parse()
.unwrap();
let nymd_url = config.get_nymd_validator_url();
let mixnet_contract = config
.get_mixnet_contract_address()
.parse()
.expect("the mixnet contract address is invalid!");
let mnemonic = config
.get_mnemonic()
.parse()
.expect("the mnemonic is invalid!");
let client_config = validator_client::Config::new(nymd_url, api_url, Some(mixnet_contract));
let inner = validator_client::Client::new_signing(client_config, mnemonic)
.expect("Failed to connect to nymd!");
Client(Arc::new(RwLock::new(inner)))
}
}
impl<C> Client<C> {
pub(crate) async fn get_mixnodes(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
self.0.read().await.get_all_nymd_mixnodes().await
}
pub(crate) async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError>
where
C: CosmWasmClient + Sync,
{
self.0.read().await.get_all_nymd_gateways().await
}
#[allow(dead_code)]
pub(crate) async fn some_rewarding_stuff_here(&self) {
todo!()
}
}
@@ -0,0 +1,113 @@
use crate::coin::{Coin, Denom};
use crate::config::Config;
use crate::error::BackendError;
use crate::format_err;
use crate::state::State;
use bip39::{Language, Mnemonic};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::RwLock;
use ts_rs::TS;
use validator_client::nymd::{AccountId, NymdClient, SigningNymdClient};
#[derive(TS, Serialize, Deserialize)]
pub struct Account {
contract_address: String,
client_address: String,
denom: Denom,
mnemonmic: Option<String>,
}
#[derive(TS, Serialize, Deserialize)]
pub struct Balance {
coin: Coin,
printable_balance: String,
}
#[tauri::command]
pub async fn connect_with_mnemonic(
mnemonic: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, String> {
let mnemonic = match Mnemonic::from_str(&mnemonic) {
Ok(mnemonic) => mnemonic,
Err(e) => return Err(BackendError::from(e).to_string()),
};
let client;
{
let r_state = state.read().await;
client = _connect_with_mnemonic(mnemonic, &r_state.config());
}
let contract_address = match client.contract_address() {
Ok(address) => address.to_string(),
Err(e) => return Err(format_err!(e)),
};
let client_address = client.address().to_string();
let denom = match client.denom() {
Ok(denom) => denom,
Err(e) => return Err(format_err!(e)),
};
let account = Account {
contract_address,
client_address,
denom: Denom::from_str(&denom.to_string())?,
mnemonmic: None,
};
let mut w_state = state.write().await;
w_state.set_client(client);
Ok(account)
}
#[tauri::command]
pub async fn get_balance(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<Balance, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.get_balance(client.address()).await {
Ok(Some(coin)) => {
let coin = Coin::new(
&coin.amount.to_string(),
&Denom::from_str(&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()),
}
}
#[tauri::command]
pub async fn create_new_account(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Account, String> {
let mnemonic = random_mnemonic();
let mut client = connect_with_mnemonic(mnemonic.to_string(), state).await?;
client.mnemonmic = Some(mnemonic.to_string());
Ok(client)
}
fn random_mnemonic() -> Mnemonic {
let mut rng = rand::thread_rng();
Mnemonic::generate_in_with(&mut rng, Language::English, 24).unwrap()
}
fn _connect_with_mnemonic(mnemonic: Mnemonic, config: &Config) -> NymdClient<SigningNymdClient> {
match NymdClient::connect_with_mnemonic(
config.get_nymd_validator_url().unwrap(),
Some(AccountId::from_str(&config.get_mixnet_contract_address()).unwrap()),
mnemonic,
) {
Ok(client) => client,
Err(e) => panic!("{}", e),
}
}
@@ -0,0 +1,84 @@
use crate::format_err;
use crate::state::State;
use cosmwasm_std::Decimal;
use cosmwasm_std::Uint128;
use mixnet_contract::StateParams;
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use std::sync::Arc;
use tokio::sync::RwLock;
use ts_rs::TS;
#[derive(Serialize, Deserialize, TS)]
pub struct TauriStateParams {
epoch_length: u32,
minimum_mixnode_bond: String,
minimum_gateway_bond: String,
mixnode_bond_reward_rate: String,
gateway_bond_reward_rate: String,
mixnode_delegation_reward_rate: String,
gateway_delegation_reward_rate: String,
mixnode_active_set_size: u32,
}
impl From<StateParams> for TauriStateParams {
fn from(p: StateParams) -> TauriStateParams {
TauriStateParams {
epoch_length: p.epoch_length,
minimum_mixnode_bond: p.minimum_mixnode_bond.to_string(),
minimum_gateway_bond: p.minimum_gateway_bond.to_string(),
mixnode_bond_reward_rate: p.mixnode_bond_reward_rate.to_string(),
gateway_bond_reward_rate: p.gateway_bond_reward_rate.to_string(),
mixnode_delegation_reward_rate: p.mixnode_delegation_reward_rate.to_string(),
gateway_delegation_reward_rate: p.gateway_delegation_reward_rate.to_string(),
mixnode_active_set_size: p.mixnode_active_set_size,
}
}
}
impl TryFrom<TauriStateParams> for StateParams {
type Error = Box<dyn std::error::Error>;
fn try_from(p: TauriStateParams) -> Result<StateParams, Self::Error> {
Ok(StateParams {
epoch_length: p.epoch_length,
minimum_mixnode_bond: Uint128::try_from(p.minimum_mixnode_bond.as_str())?,
minimum_gateway_bond: Uint128::try_from(p.minimum_gateway_bond.as_str())?,
mixnode_bond_reward_rate: Decimal::from_str(p.mixnode_bond_reward_rate.as_str())?,
gateway_bond_reward_rate: Decimal::from_str(p.gateway_bond_reward_rate.as_str())?,
mixnode_delegation_reward_rate: Decimal::from_str(p.mixnode_delegation_reward_rate.as_str())?,
gateway_delegation_reward_rate: Decimal::from_str(p.gateway_delegation_reward_rate.as_str())?,
mixnode_active_set_size: p.mixnode_active_set_size,
})
}
}
#[tauri::command]
pub async fn get_state_params(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriStateParams, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.get_state_params().await {
Ok(params) => Ok(params.into()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn update_state_params(
params: TauriStateParams,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriStateParams, String> {
let r_state = state.read().await;
let client = r_state.client()?;
let state_params: StateParams = match params.try_into() {
Ok(state_params) => state_params,
Err(e) => return Err(format_err!(e)),
};
match client.update_state_params(state_params.clone()).await {
Ok(_) => Ok(state_params.into()),
Err(e) => Err(format_err!(e)),
}
}
@@ -0,0 +1,64 @@
use crate::coin::Coin;
use crate::format_err;
use crate::state::State;
use crate::{Gateway, MixNode};
use cosmwasm_std::Coin as CosmWasmCoin;
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
#[tauri::command]
pub async fn bond_gateway(
gateway: Gateway,
bond: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match bond.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.bond_gateway(gateway, bond).await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn unbond_gateway(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<(), String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.unbond_gateway().await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn unbond_mixnode(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<(), String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.unbond_mixnode().await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn bond_mixnode(
mixnode: MixNode,
bond: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match bond.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.bond_mixnode(mixnode, bond).await {
Ok(_result) => Ok(()),
Err(e) => Err(format_err!(e)),
}
}
@@ -0,0 +1,94 @@
use crate::coin::Coin;
use crate::format_err;
use crate::state::State;
use cosmwasm_std::Coin as CosmWasmCoin;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
use ts_rs::TS;
#[derive(TS, Serialize, Deserialize)]
pub struct DelegationResult {
source_address: String,
target_address: String,
amount: Option<Coin>,
}
#[tauri::command]
pub async fn delegate_to_mixnode(
identity: &str,
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match amount.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.delegate_to_mixnode(identity, &bond).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: Some(bond.into()),
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn undelegate_from_mixnode(
identity: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.remove_mixnode_delegation(identity).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: None,
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn delegate_to_gateway(
identity: &str,
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let bond: CosmWasmCoin = match amount.try_into() {
Ok(b) => b,
Err(e) => return Err(format_err!(e)),
};
let client = r_state.client()?;
match client.delegate_to_gateway(identity, &bond).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: Some(bond.into()),
}),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn undelegate_from_gateway(
identity: &str,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.remove_gateway_delegation(identity).await {
Ok(_result) => Ok(DelegationResult {
source_address: client.address().to_string(),
target_address: identity.to_string(),
amount: None,
}),
Err(e) => Err(format_err!(e)),
}
}
@@ -0,0 +1,5 @@
pub mod account;
pub mod admin;
pub mod bond;
pub mod delegate;
pub mod send;
@@ -0,0 +1,69 @@
use crate::coin::Coin;
use crate::format_err;
use crate::state::State;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use std::str::FromStr;
use std::sync::Arc;
use tendermint_rpc::endpoint::broadcast::tx_commit::Response;
use tokio::sync::RwLock;
use ts_rs::TS;
use validator_client::nymd::{AccountId, CosmosCoin};
#[derive(Deserialize, Serialize, TS)]
pub struct TauriTxResult {
code: u32,
gas_wanted: u64,
gas_used: u64,
block_height: u64,
details: TransactionDetails,
}
#[derive(Deserialize, Serialize, TS)]
pub 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,
}
}
}
#[tauri::command]
pub 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)),
};
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;
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,
},
)),
Err(e) => Err(format_err!(e)),
}
}
+54
View File
@@ -0,0 +1,54 @@
use crate::coin::{Coin, Denom};
use crate::format_err;
use crate::state::State;
use crate::Operation;
use std::sync::Arc;
use tokio::sync::RwLock;
#[tauri::command]
pub fn major_to_minor(amount: &str) -> Result<Coin, String> {
let coin = Coin::new(amount, &Denom::Major);
Ok(coin.to_minor())
}
#[tauri::command]
pub fn minor_to_major(amount: &str) -> Result<Coin, String> {
let coin = Coin::new(amount, &Denom::Minor);
Ok(coin.to_major())
}
#[tauri::command]
pub async fn owns_mixnode(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<bool, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.owns_mixnode(client.address()).await {
Ok(o) => Ok(o),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn owns_gateway(state: tauri::State<'_, Arc<RwLock<State>>>) -> Result<bool, String> {
let r_state = state.read().await;
let client = r_state.client()?;
match client.owns_gateway(client.address()).await {
Ok(o) => Ok(o),
Err(e) => Err(format_err!(e)),
}
}
#[tauri::command]
pub async fn get_fee(
operation: Operation,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<Coin, String> {
let r_state = state.read().await;
let client = r_state.client()?;
let fee = client.get_fee(operation);
let mut coin = Coin::new("0", &Denom::Major);
for f in fee.amount {
coin = coin + f.into();
}
Ok(coin)
}
+8
View File
@@ -0,0 +1,8 @@
import { Denom } from "./denom";
export interface Account {
contract_address: string;
client_address: string;
denom: Denom;
mnemonmic: string | null;
}
@@ -0,0 +1,10 @@
export interface TauriStateParams {
epoch_length: number;
minimum_mixnode_bond: string;
minimum_gateway_bond: string;
mixnode_bond_reward_rate: string;
gateway_bond_reward_rate: string;
mixnode_delegation_reward_rate: string;
gateway_delegation_reward_rate: string;
mixnode_active_set_size: number;
}