Skip to content

Commit

Permalink
feat: add approve-all command to batch approvals (#51)
Browse files Browse the repository at this point in the history
* improvements on logging and code quality

* feat: add approve-all command to batch approvals
  • Loading branch information
willyrgf authored Jul 5, 2023
1 parent 5fd32e5 commit 2455ab2
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mfm"
version = "0.1.28"
version = "0.1.29"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
24 changes: 24 additions & 0 deletions src/approve_all/cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use clap::{ArgMatches, Command};

pub fn generate() -> Command {
Command::new("approve-all")
.about("Approve all configured token spending (needed to swap tokens)")
.arg(
clap::arg!(-w --"wallet" <WALLET_NAME> "Wallet id from config file")
.required(true),
)
.arg(
clap::arg!(-n --"network" <bsc> "Network to run all approvals")
.required(true),
)
.arg(
clap::arg!(-a --"amount" <VALUE> "Amount to allow spending: default is the current balance")
.required(false)
.value_parser(clap::value_parser!(f64)),
)
}

#[tracing::instrument(name = "approve_all call command", level = "debug")]
pub async fn call_sub_commands(args: &ArgMatches) -> Result<(), anyhow::Error> {
super::run(args).await
}
45 changes: 45 additions & 0 deletions src/approve_all/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::{cmd::helpers, config::Config};
use clap::ArgMatches;

pub mod cmd;

#[tracing::instrument(name = "run approve-all", skip(args))]
async fn run(args: &ArgMatches) -> Result<(), anyhow::Error> {
let wallet = helpers::get_wallet(args)?;
let network = helpers::get_network(args)?;
let config = Config::global();

let assets = config.assets.assets_by_network(network)?;
let exchanges = network.get_exchanges();

for asset in assets {
let asset_decimals = asset.decimals().await.unwrap();
let amount = helpers::get_amount(args, asset_decimals).unwrap_or(asset.balance_of(wallet.address()).await?);
tracing::debug!("amount: {:?}", amount);

for exchange in exchanges.iter() {
let allowance_amount = asset.allowance(wallet.address(), exchange.as_router_address().unwrap()).await;
if allowance_amount >= amount {
tracing::info!("current amount allowed is greater or equal --amount, to {} on {} for {} with spender {}", asset.name(), exchange.name(), amount, wallet.address());
continue;
}

tracing::info!("running approve_spender to {} on {} for {} with spender {}", asset.name(), exchange.name(), amount, wallet.address());
asset
.approve_spender(wallet, exchange.as_router_address().unwrap(), amount)
.await
.unwrap();

let remaning = asset
.allowance(wallet.address(), exchange.as_router_address().unwrap())
.await;
tracing::info!(
"approved_spender allowance remaning on {}, to spend: {:?}, asset_decimals: {}",
asset.name(),
remaning,
asset_decimals
);
}
}
Ok(())
}
2 changes: 1 addition & 1 deletion src/asset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl Asset {
}

// TODO: validate it in the initialization of Asset
#[tracing::instrument(name = "get decimals from asset contract")]
#[tracing::instrument(name = "get decimals from asset contract", level = "debug")]
pub async fn decimals(&self) -> Result<u8, anyhow::Error> {
self.contract()
.query("decimals", (), None, Options::default(), None)
Expand Down
25 changes: 0 additions & 25 deletions src/cmd/enc.rs
Original file line number Diff line number Diff line change
@@ -1,25 +0,0 @@
use crate::utils::{self, password::encrypt_private_key_to_base64};
use clap::{ArgMatches, Command};

pub const COMMAND: &str = "enc";

pub fn generate_cmd<'a>() -> Command {
Command::new(COMMAND).about("Encrypt data with a password")
}

pub async fn call_sub_commands(_: &ArgMatches) {
let password = utils::password::prompt_password("Type a password: ").unwrap_or_else(|e| {
tracing::error!(error = %e);
panic!()
});

let private_key = utils::password::prompt_password("Paste the wallet private key: ")
.unwrap_or_else(|e| {
tracing::error!(error = %e);
panic!()
});

let base64 = encrypt_private_key_to_base64(password, private_key);

println!("Encrypted key as base64: {}", base64);
}
24 changes: 12 additions & 12 deletions src/cmd/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use web3::types::{Address, H160, U256};

//TODO: add constants to all keys in value_of

#[tracing::instrument(name = "get exchange from command args")]
#[tracing::instrument(name = "get exchange from command args", level = "debug", skip(args))]
pub fn get_exchange(args: &ArgMatches) -> Result<&Exchange, anyhow::Error> {
match args.get_one::<String>("exchange") {
Some(n) => {
Expand All @@ -29,7 +29,7 @@ pub fn get_exchange(args: &ArgMatches) -> Result<&Exchange, anyhow::Error> {
}
}

#[tracing::instrument(name = "get network from command args")]
#[tracing::instrument(name = "get network from command args", level = "debug", skip(args))]
pub fn get_network(args: &ArgMatches) -> Result<&Network, anyhow::Error> {
match args.get_one::<String>("network") {
Some(n) => {
Expand All @@ -43,15 +43,15 @@ pub fn get_network(args: &ArgMatches) -> Result<&Network, anyhow::Error> {
}
}

#[tracing::instrument(name = "get address from command args")]
#[tracing::instrument(name = "get address from command args", level = "debug", skip(args))]
pub fn get_address(args: &ArgMatches) -> Result<H160, anyhow::Error> {
match args.get_one::<String>("address") {
Some(a) => Address::from_str(a).map_err(|e| anyhow::anyhow!(e)),
None => Err(anyhow::anyhow!("--address is required")),
}
}

#[tracing::instrument(name = "get wallet from command args")]
#[tracing::instrument(name = "get wallet from command args", level = "debug", skip(args))]
pub fn get_wallet(args: &ArgMatches) -> Result<&Wallet, anyhow::Error> {
let config = Config::global();
match args.get_one::<String>("wallet") {
Expand Down Expand Up @@ -98,23 +98,23 @@ pub fn get_txn_id(args: &ArgMatches) -> &str {
}
}

#[tracing::instrument(name = "get amount from command args")]
#[tracing::instrument(name = "get amount from command args", skip(args), level = "debug")]
pub fn get_amount(args: &ArgMatches, asset_decimals: u8) -> Result<U256, anyhow::Error> {
match args.get_one::<f64>("amount") {
Some(amount) => Ok(math::f64_to_u256(*amount, asset_decimals)),
None => Err(anyhow::anyhow!("--amount is not a number")),
}
}

#[tracing::instrument(name = "get amount in f64 from command args")]
#[tracing::instrument(name = "get amount in f64 from command args", level = "debug", skip(args))]
pub fn get_amount_f64(args: &ArgMatches) -> Result<f64, anyhow::Error> {
match args.get_one::<f64>("amount") {
Some(amount) => Ok(*amount),
None => Err(anyhow::anyhow!("--amount is not a number")),
}
}

#[tracing::instrument(name = "get slippage in f64 from command args")]
#[tracing::instrument(name = "get slippage in f64 from command args", level = "debug", skip(args))]
pub fn get_slippage(args: &ArgMatches) -> Result<f64, anyhow::Error> {
match args.get_one::<f64>("slippage") {
Some(f) if *f > 0.0 && *f <= 100.0 => Ok(*f),
Expand All @@ -126,7 +126,7 @@ pub fn get_slippage(args: &ArgMatches) -> Result<f64, anyhow::Error> {
}
}

#[tracing::instrument(name = "get input token in network from command args")]
#[tracing::instrument(name = "get input token in network from command args", level = "debug", skip(args))]
pub fn get_token_input_in_network_from_args(
args: &ArgMatches,
network_id: &str,
Expand All @@ -141,7 +141,7 @@ pub fn get_token_input_in_network_from_args(
}
}

#[tracing::instrument(name = "get output token in network from command args")]
#[tracing::instrument(name = "get output token in network from command args", level = "debug", skip(args))]
pub fn get_token_output_in_network_from_args(
args: &ArgMatches,
network_id: &str,
Expand Down Expand Up @@ -184,20 +184,20 @@ pub fn get_withdraw_wallet(args: &ArgMatches) -> WithdrawWallet {
}
}

#[tracing::instrument(name = "get hide zero from command args")]
#[tracing::instrument(name = "get hide zero from command args", level = "debug", skip(args))]
pub fn get_hide_zero(args: &ArgMatches) -> bool {
match args.get_one::<String>("hide-zero") {
Some(b) => b.parse().unwrap_or(false),
_ => false,
}
}

#[tracing::instrument(name = "get run every from command args")]
#[tracing::instrument(name = "get run every from command args", level = "debug", skip(args))]
pub fn get_run_every(args: &ArgMatches) -> Option<&u32> {
args.get_one::<u32>("run-every")
}

#[tracing::instrument(name = "get track from command args")]
#[tracing::instrument(name = "get track from command args", level = "debug", skip(args))]
pub fn get_track(args: &ArgMatches) -> bool {
match args.get_one::<String>("track") {
Some(b) => b.parse().unwrap_or(false),
Expand Down
12 changes: 8 additions & 4 deletions src/cmd/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
allowance, approve, balances, encrypt, quote, rebalancer, swap, track, unwrap, withdraw, wrap, watcher,
allowance, approve, balances, encrypt, quote, rebalancer, swap, track, unwrap, withdraw, wrap, watcher, approve_all,
};
use crate::{config::Config, APP_NAME};
use clap::{crate_version, ArgMatches, Command};
Expand All @@ -22,6 +22,8 @@ pub enum Commands {
Track,
Encrypt,
Watcher,
#[serde(rename = "approve-all")]
ApproveAll,
}

impl Commands {
Expand All @@ -39,6 +41,7 @@ impl Commands {
Self::Quote => quote::cmd::call_sub_commands(args).await,
Self::Track => track::cmd::call_sub_commands(args).await,
Self::Watcher => watcher::cmd::call_sub_commands(args).await,
Self::ApproveAll => approve_all::cmd::call_sub_commands(args).await,
}
}
}
Expand All @@ -65,23 +68,24 @@ pub fn new() -> Command {
.subcommand(quote::cmd::generate())
.subcommand(track::cmd::generate())
.subcommand(watcher::cmd::generate())
.subcommand(approve_all::cmd::generate())
}

#[tracing::instrument(name = "lookup command from cli")]
#[tracing::instrument(name = "lookup command from cli", level = "debug")]
pub fn lookup_command(cmd: &str) -> Result<Commands, anyhow::Error> {
let json_cmd = format!("\"{}\"", cmd);
serde_json::from_str(json_cmd.as_str()).map_err(|e| anyhow::anyhow!(e))
}

#[tracing::instrument(name = "call commands")]
#[tracing::instrument(name = "call commands", level = "debug")]
pub async fn call_sub_commands(matches: &ArgMatches) -> Result<(), anyhow::Error> {
match matches.subcommand() {
Some((cmd, sub_matches)) => lookup_command(cmd)?.run(sub_matches).await,
_ => Err(anyhow::anyhow!("subcommand is required")),
}
}

#[tracing::instrument(name = "cli run command", skip(cmd))]
#[tracing::instrument(name = "cli run command", level = "debug")]
pub async fn run(cmd: Command) -> Result<(), anyhow::Error> {
let cmd_matches = cmd.get_matches();

Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ pub mod utils;
pub mod watcher;
pub mod withdraw;
pub mod wrap;
pub mod approve_all;

pub const APP_NAME: &str = "mfm";
pub const DEFAULT_LOG_LEVEL: &str = "warn";
pub const DEFAULT_LOG_LEVEL: &str = "info";

// Since the exit code names e.g. `SIGBUS` are most appropriate yet trigger a test error with the
// clippy lint `upper_case_acronyms` we have disabled this lint for this enum.
Expand Down
1 change: 1 addition & 0 deletions src/rebalancer/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ async fn cmd_run(args: &ArgMatches) -> Result<(), anyhow::Error> {
}
Strategy::DiffParking => {
tracing::debug!("rebalancer::cmd::call_sub_commands() Strategy::DiffParking");
tracing::info!("running run_diff_parking by Strategy::DiffParking");
rebalancer::run_diff_parking(&config).await
}
}
Expand Down
1 change: 1 addition & 0 deletions src/rebalancer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ pub async fn run_diff_parking_per_kind(

tracing::debug!("diff_parking: parking_to_asset: asset_in.name: {}, asset_out.name: {}, amount_in: {:?}, amount_out: {:?}", asset_in.name(), asset_out.name(), amount_in, amount_out);

tracing::info!("run_diff_parking_per_kind: move_asset_with_slippage: asset_in ({}), asset_out ({}), amount_in ({:?}), amount_out ({:?})", asset_in.name(), asset_out.name(), amount_in, amount_out);
move_asset_with_slippage(config, asset_in, asset_out, amount_in, amount_out).await
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/track/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn generate() -> Command {
)
}

#[tracing::instrument(name = "track call command")]
#[tracing::instrument(name = "track call command", level = "debug")]
pub async fn call_sub_commands(args: &ArgMatches) -> Result<(), anyhow::Error> {
super::run(args).await
}
2 changes: 1 addition & 1 deletion src/track/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct TrackPortfolioState {
data: TrackPortfolioStateData,
}

#[tracing::instrument(name = "wrapped run track")]
#[tracing::instrument(name = "wrapped run track", level = "debug")]
pub(crate) async fn wrapped_run(args: &ArgMatches) -> Result<(), anyhow::Error> {
let config = Config::global();
let (api_token, api_address) = match &config.server {
Expand Down

0 comments on commit 2455ab2

Please sign in to comment.