Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto fill transaction #80

Merged
merged 1 commit into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .cargo-husky/hooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ set -e
echo 'Running all pre-commit checks:'
cargo fmt
cargo test --no-default-features --features core,models,utils
cargo test --no-default-features --features core,models,utils,embedded-ws
cargo test --no-default-features --features core,models,utils,tungstenite
cargo test --no-default-features --features std,models,utils,websocket,websocket-codec
cargo test --no-default-features --features core,models,utils,websocket-std
cargo test --no-default-features --features core,models,utils,json-rpc-std
cargo test --no-default-features --features websocket-std,helpers
cargo test --all-features
cargo clippy --fix --allow-staged
cargo doc --no-deps
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/unit_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,8 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features core,models,websocket
args: --no-default-features --features std,models,websocket,websocket-codec
- uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features websocket-std,helpers
13 changes: 12 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,23 @@ name = "benchmarks"
harness = false

[features]
default = ["std", "core", "models", "utils", "websocket-std"]
default = ["std", "core", "models", "utils", "helpers", "websocket-std"]
models = ["core", "transactions", "requests", "ledger", "results"]
transactions = ["core", "amounts", "currencies"]
requests = ["core", "amounts", "currencies"]
results = ["core", "amounts", "currencies"]
ledger = ["core", "amounts", "currencies"]
helpers = ["account-helpers", "ledger-helpers", "transaction-helpers"]
account-helpers = ["amounts", "currencies", "requests", "results"]
ledger-helpers = ["amounts", "currencies", "requests", "results"]
transaction-helpers = [
"amounts",
"currencies",
"requests",
"results",
"transactions",
"ledger",
]
amounts = ["core"]
currencies = ["core"]
json-rpc = ["url", "reqwless", "embedded-nal-async"]
Expand Down
2 changes: 1 addition & 1 deletion examples/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ path = "src/bin/wallet/generate_wallet.rs"
required-features = []

[[bin]]
name = "tungstenite"
name = "websocket-std"
path = "src/bin/tokio/net/tungstenite.rs"
required-features = ["tokio"]

Expand Down
52 changes: 52 additions & 0 deletions src/asynch/account/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use alloc::borrow::Cow;
use anyhow::Result;

use crate::{
core::addresscodec::{is_valid_xaddress, xaddress_to_classic_address},
models::{ledger::AccountRoot, requests::AccountInfo, results},
Err,
};

use super::clients::AsyncClient;

pub async fn get_next_valid_seq_number(
address: Cow<'_, str>,
client: &impl AsyncClient,
ledger_index: Option<Cow<'_, str>>,
) -> Result<u32> {
let account_info =
get_account_root(address, client, ledger_index.unwrap_or("current".into())).await?;
Ok(account_info.sequence)
}

pub async fn get_account_root<'a>(
address: Cow<'a, str>,
client: &impl AsyncClient,
ledger_index: Cow<'a, str>,
) -> Result<AccountRoot<'a>> {
let mut classic_address = address;
if is_valid_xaddress(&classic_address) {
classic_address = match xaddress_to_classic_address(&classic_address) {
Ok(addr) => addr.0.into(),
Err(e) => return Err!(e),
};
}
let account_info = client
.request(
AccountInfo::new(
None,
classic_address,
None,
Some(ledger_index),
None,
None,
None,
)
.into(),
)
.await?;

Ok(account_info
.try_into_result::<results::AccountInfo<'_>>()?
.account_data)
}
20 changes: 18 additions & 2 deletions src/asynch/clients/async_client.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
use super::client::Client;
use crate::models::{requests::XRPLRequest, results::XRPLResponse};
use super::{client::Client, CommonFields};
use crate::models::{
requests::{ServerState, XRPLRequest},
results::{ServerState as ServerStateResult, XRPLResponse},
};
use anyhow::Result;

#[allow(async_fn_in_trait)]
pub trait AsyncClient: Client {
async fn request<'a: 'b, 'b>(&self, request: XRPLRequest<'a>) -> Result<XRPLResponse<'b>> {
self.request_impl(request).await
}

async fn get_common_fields(&self) -> Result<CommonFields<'_>> {
let server_state = self.request(ServerState::new(None).into()).await?;
let state = server_state
.try_into_result::<ServerStateResult<'_>>()?
.state;
let common_fields = CommonFields {
network_id: state.network_id,
build_version: Some(state.build_version),
};

Ok(common_fields)
}
}

impl<T: Client> AsyncClient for T {}
8 changes: 8 additions & 0 deletions src/asynch/clients/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod json_rpc;
#[cfg(any(feature = "websocket-std", feature = "websocket"))]
pub mod websocket;

use alloc::borrow::Cow;
use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
pub type MultiExecutorMutex = CriticalSectionRawMutex;
pub type SingleExecutorMutex = NoopRawMutex;
Expand All @@ -13,5 +14,12 @@ pub use async_client::*;
pub use client::*;
#[cfg(any(feature = "json-rpc-std", feature = "json-rpc"))]
pub use json_rpc::*;
use serde::{Deserialize, Serialize};
#[cfg(any(feature = "websocket-std", feature = "websocket"))]
pub use websocket::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommonFields<'a> {
pub build_version: Option<Cow<'a, str>>,
pub network_id: Option<u32>,
}
2 changes: 1 addition & 1 deletion src/asynch/clients/websocket/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
models::{requests::XRPLRequest, results::XRPLResponse},
Err,

Check warning on line 3 in src/asynch/clients/websocket/mod.rs

View workflow job for this annotation

GitHub Actions / xrpl-rust

unused import: `Err`

Check warning on line 3 in src/asynch/clients/websocket/mod.rs

View workflow job for this annotation

GitHub Actions / xrpl-rust

unused import: `Err`

Check warning on line 3 in src/asynch/clients/websocket/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `Err`

warning: unused import: `Err` --> src/asynch/clients/websocket/mod.rs:3:5 | 3 | Err, | ^^^ | = note: `#[warn(unused_imports)]` on by default
};
#[cfg(all(feature = "websocket-std", not(feature = "websocket")))]
use alloc::string::String;
Expand All @@ -15,11 +15,11 @@
use futures::{Sink, SinkExt, Stream, StreamExt};

mod websocket_base;
use websocket_base::MessageHandler;

Check warning on line 18 in src/asynch/clients/websocket/mod.rs

View workflow job for this annotation

GitHub Actions / xrpl-rust

unused import: `websocket_base::MessageHandler`

Check warning on line 18 in src/asynch/clients/websocket/mod.rs

View workflow job for this annotation

GitHub Actions / xrpl-rust

unused import: `websocket_base::MessageHandler`

Check warning on line 18 in src/asynch/clients/websocket/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `websocket_base::MessageHandler`

warning: unused import: `websocket_base::MessageHandler` --> src/asynch/clients/websocket/mod.rs:18:5 | 18 | use websocket_base::MessageHandler; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

#[cfg(all(feature = "websocket", not(feature = "websocket-std")))]
mod _no_std;
#[cfg(feature = "websocket-codec")]
#[cfg(all(feature = "websocket-codec", feature = "std"))]
pub mod codec;
mod exceptions;
pub use exceptions::XRPLWebsocketException;
Expand Down
71 changes: 71 additions & 0 deletions src/asynch/ledger/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use core::{cmp::min, convert::TryInto};

use alloc::string::ToString;
use anyhow::Result;

use crate::models::{
amount::XRPAmount,
requests::{Fee, Ledger},
results::{Drops, Fee as FeeResult, Ledger as LedgerResult},
};

use super::clients::AsyncClient;

pub async fn get_latest_validated_ledger_sequence(client: &impl AsyncClient) -> Result<u32> {
let ledger_response = client
.request(
Ledger::new(
None,
None,
None,
None,
None,
None,
Some("validated".into()),
None,
None,
None,
)
.into(),
)
.await?;

Ok(ledger_response
.try_into_result::<LedgerResult<'_>>()?
.ledger_index)
}

pub enum FeeType {
Open,
Minimum,
Dynamic,
}

pub async fn get_fee(
client: &impl AsyncClient,
max_fee: Option<u32>,
fee_type: Option<FeeType>,
) -> Result<XRPAmount<'_>> {
let fee_request = Fee::new(None);
match client.request(fee_request.into()).await {
Ok(response) => {
let drops = response.try_into_result::<FeeResult<'_>>()?.drops;
let fee = match_fee_type(fee_type, drops)?;

if let Some(max_fee) = max_fee {
Ok(XRPAmount::from(min(max_fee, fee).to_string()))
} else {
Ok(XRPAmount::from(fee.to_string()))
}
}
Err(err) => Err(err),
}
}

fn match_fee_type(fee_type: Option<FeeType>, drops: Drops<'_>) -> Result<u32> {
match fee_type {
None | Some(FeeType::Open) => Ok(drops.open_ledger_fee.try_into()?),
Some(FeeType::Minimum) => Ok(drops.minimum_fee.try_into()?),
Some(FeeType::Dynamic) => unimplemented!("Dynamic fee calculation not yet implemented"),
}
}
6 changes: 6 additions & 0 deletions src/asynch/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
#[cfg(feature = "account-helpers")]
pub mod account;
#[cfg(any(
feature = "websocket-std",
feature = "websocket",
feature = "json-rpc-std",
feature = "json-rpc"
))]
pub mod clients;
#[cfg(feature = "ledger-helpers")]
pub mod ledger;
#[cfg(feature = "transaction-helpers")]
pub mod transaction;
16 changes: 16 additions & 0 deletions src/asynch/transaction/exceptions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use core::num::ParseIntError;

use alloc::borrow::Cow;
use thiserror_no_std::Error;

use crate::models::amount::XRPAmount;

#[derive(Error, Debug, PartialEq)]
pub enum XRPLTransactionException<'a> {
#[error("Fee of {0:?} Drops is much higher than a typical XRP transaction fee. This may be a mistake. If intentional, please use `check_fee = false`")]
FeeUnusuallyHigh(XRPAmount<'a>),
#[error("Unable to parse rippled version: {0}")]
ParseRippledVersionError(ParseIntError),
#[error("Invalid rippled version: {0}")]
InvalidRippledVersion(Cow<'a, str>),
}
Loading
Loading