diff --git a/crates/erc20_payment_lib/src/eth.rs b/crates/erc20_payment_lib/src/eth.rs index 9e3a670b..1d86d9fc 100644 --- a/crates/erc20_payment_lib/src/eth.rs +++ b/crates/erc20_payment_lib/src/eth.rs @@ -93,6 +93,12 @@ pub fn deposit_id_from_nonce(funder: Address, nonce: u64) -> U256 { U256::from_big_endian(&slice) } +pub fn nonce_from_deposit_id(deposit_id: U256) -> u64 { + let mut slice: [u8; 32] = [0; 32]; + deposit_id.to_big_endian(&mut slice); + u64::from_be_bytes(slice[24..32].try_into().unwrap()) +} + pub async fn get_deposit_details( web3: Arc, deposit_id: U256, diff --git a/crates/erc20_payment_lib/src/runtime.rs b/crates/erc20_payment_lib/src/runtime.rs index 84958309..198cc5a3 100644 --- a/crates/erc20_payment_lib/src/runtime.rs +++ b/crates/erc20_payment_lib/src/runtime.rs @@ -27,7 +27,7 @@ use crate::account_balance::{test_balance_loop, BalanceOptions2}; use crate::config::AdditionalOptions; use crate::contracts::CreateDepositArgs; use crate::eth::{ - deposit_id_from_nonce, get_eth_addr_from_secret, get_latest_block_info, DepositDetails, + get_eth_addr_from_secret, get_latest_block_info, nonce_from_deposit_id, DepositDetails, }; use crate::sender::service_loop; use crate::utils::{DecimalConvExt, StringConvExt, U256ConvExt}; @@ -1131,7 +1131,7 @@ pub struct CloseDepositOptionsInt { pub struct TerminateDepositOptionsInt { pub lock_contract_address: Address, pub skip_deposit_check: bool, - pub deposit_nonce: u64, + pub deposit_id: U256, } pub async fn close_deposit( @@ -1184,17 +1184,9 @@ pub async fn terminate_deposit( from: Address, opt: TerminateDepositOptionsInt, ) -> Result<(), PaymentError> { - let free_deposit_tx_id = create_terminate_deposit( - from, - opt.lock_contract_address, - chain_id, - None, - opt.deposit_nonce, - )?; - //let mut block_info: Option = None; if !opt.skip_deposit_check { - let deposit_id = deposit_id_from_nonce(from, opt.deposit_nonce); + let deposit_id = opt.deposit_id; let deposit_details = deposit_details(web3.clone(), deposit_id, opt.lock_contract_address).await?; if deposit_details.amount_decimal.is_zero() { @@ -1218,6 +1210,13 @@ pub async fn terminate_deposit( )); } } + let free_deposit_tx_id = create_terminate_deposit( + from, + opt.lock_contract_address, + chain_id, + None, + nonce_from_deposit_id(opt.deposit_id), + )?; let mut db_transaction = conn.begin().await.map_err(err_from!())?; let make_deposit_tx = insert_tx(&mut *db_transaction, &free_deposit_tx_id) diff --git a/src/actions/mod.rs b/src/actions.rs similarity index 96% rename from src/actions/mod.rs rename to src/actions.rs index 8ac515a8..1e5207f7 100644 --- a/src/actions/mod.rs +++ b/src/actions.rs @@ -2,11 +2,12 @@ use rustc_hex::FromHexError; use std::str::FromStr; use web3::types::Address; -pub mod close_deposit; pub mod check_rpc; +pub mod close_deposit; pub mod create_deposit; pub mod deposit_details; pub mod scan_chain; +pub mod terminate_deposit; pub fn check_address_name(n: &str) -> Result { match n { diff --git a/src/actions/close_deposit.rs b/src/actions/close_deposit.rs index 06777b8d..55a1ede3 100644 --- a/src/actions/close_deposit.rs +++ b/src/actions/close_deposit.rs @@ -23,7 +23,7 @@ pub struct CloseDepositOptions { #[structopt(long = "skip-check", help = "Skip check deposit")] pub skip_check: bool, - #[structopt(long = "deposit-id", help = "Deposit id to cancel.")] + #[structopt(long = "deposit-id", help = "Deposit id to close")] pub deposit_id: String, } diff --git a/src/actions/terminate_deposit.rs b/src/actions/terminate_deposit.rs new file mode 100644 index 00000000..4189309e --- /dev/null +++ b/src/actions/terminate_deposit.rs @@ -0,0 +1,103 @@ +use erc20_payment_lib::config::Config; +use erc20_payment_lib::eth::deposit_id_from_nonce; +use erc20_payment_lib::runtime::{terminate_deposit, TerminateDepositOptionsInt}; +use erc20_payment_lib::setup::PaymentSetup; +use erc20_payment_lib_common::err_custom_create; +use erc20_payment_lib_common::error::PaymentError; +use sqlx::SqlitePool; +use std::str::FromStr; +use structopt::StructOpt; +use web3::types::{Address, U256}; + +#[derive(StructOpt)] +#[structopt(about = "Allocate funds for use by payer")] +pub struct TerminateDepositOptions { + #[structopt(short = "c", long = "chain-name", default_value = "holesky")] + pub chain_name: String, + + #[structopt(long = "address", help = "Address (has to have private key)")] + pub address: Option
, + + #[structopt(long = "account-no", help = "Address by index (for convenience)")] + pub account_no: Option, + + #[structopt(long = "skip-check", help = "Skip check deposit")] + pub skip_check: bool, + + #[structopt(long = "deposit-id", help = "Deposit id to terminate.")] + pub deposit_id: Option, + + #[structopt(long = "deposit-nonce", help = "Deposit nonce to terminate.")] + pub deposit_nonce: Option, +} + +pub async fn terminate_deposit_local( + conn: SqlitePool, + terminate_deposit_options: TerminateDepositOptions, + config: Config, + public_addrs: &[Address], +) -> Result<(), PaymentError> { + log::info!("Making deposit..."); + let public_addr = if let Some(address) = terminate_deposit_options.address { + address + } else if let Some(account_no) = terminate_deposit_options.account_no { + *public_addrs + .get(account_no) + .expect("No public adss found with specified account_no") + } else { + *public_addrs.first().expect("No public adss found") + }; + let chain_cfg = config + .chain + .get(&terminate_deposit_options.chain_name) + .ok_or(err_custom_create!( + "Chain {} not found in config file", + terminate_deposit_options.chain_name + ))?; + + let payment_setup = PaymentSetup::new_empty(&config)?; + let web3 = payment_setup.get_provider(chain_cfg.chain_id)?; + + if terminate_deposit_options.deposit_id.is_some() + && terminate_deposit_options.deposit_nonce.is_some() + { + return Err(err_custom_create!("Invalid parameters: only one of `deposit_id` or `deposit_nonce` should be provided to terminate a deposit")); + } + + let deposit_id = match ( + terminate_deposit_options.deposit_id, + terminate_deposit_options.deposit_nonce, + ) { + (Some(deposit_id), None) => U256::from_str(&deposit_id) + .map_err(|e| err_custom_create!("Invalid deposit id: {}", e))?, + (None, Some(deposit_nonce)) => deposit_id_from_nonce(public_addr, deposit_nonce), + (Some(_), Some(_)) => { + return Err(err_custom_create!("Invalid parameters: only one of `deposit_id` or `deposit_nonce` should be provided to terminate a deposit")); + } + (None, None) => { + return Err(err_custom_create!("Missing required parameters: either `deposit_id` or `deposit_nonce` must be provided to terminate a deposit")); + } + }; + + terminate_deposit( + web3, + &conn, + chain_cfg.chain_id as u64, + public_addr, + TerminateDepositOptionsInt { + lock_contract_address: chain_cfg + .lock_contract + .clone() + .map(|c| c.address) + .expect("No lock contract found"), + deposit_id, + skip_deposit_check: terminate_deposit_options.skip_check, + }, + ) + .await?; + println!( + "terminate_deposit added to queue successfully deposit id: {}", + deposit_id, + ); + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 3c0955dc..fd980f07 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,11 +24,12 @@ use erc20_payment_lib::{ use std::env; use std::str::FromStr; -use crate::actions::close_deposit::close_deposit_local; use crate::actions::check_address_name; use crate::actions::check_rpc::check_rpc_local; +use crate::actions::close_deposit::close_deposit_local; use crate::actions::create_deposit::make_deposit_local; use crate::actions::deposit_details::deposit_details_local; +use crate::actions::terminate_deposit::terminate_deposit_local; use crate::stats::{export_stats, run_stats}; use erc20_payment_lib::faucet_client::faucet_donate; use erc20_payment_lib::misc::gen_private_keys; @@ -73,6 +74,7 @@ async fn main_internal() -> Result<(), PaymentError> { PaymentCommands::MintTestTokens { .. } => {} PaymentCommands::CreateDeposit { .. } => {} PaymentCommands::CloseDeposit { .. } => {} + PaymentCommands::TerminateDeposit { .. } => {} PaymentCommands::CheckDeposit { .. } => {} PaymentCommands::Transfer { .. } => {} PaymentCommands::Balance { .. } => {} @@ -373,6 +375,17 @@ async fn main_internal() -> Result<(), PaymentError> { ) .await?; } + PaymentCommands::TerminateDeposit { + terminate_deposit_options, + } => { + terminate_deposit_local( + conn.clone().unwrap(), + terminate_deposit_options, + config, + &public_addrs, + ) + .await?; + } PaymentCommands::CheckDeposit { check_deposit_options, } => { diff --git a/src/options.rs b/src/options.rs index adb7d325..bccca130 100644 --- a/src/options.rs +++ b/src/options.rs @@ -2,6 +2,7 @@ use std::{fmt::Debug, path::PathBuf}; use crate::actions::close_deposit::CloseDepositOptions; use crate::actions::create_deposit::CreateDepositOptions; +use crate::actions::terminate_deposit::TerminateDepositOptions; use erc20_payment_lib_extra::{BalanceOptions, GenerateOptions}; use structopt::StructOpt; use web3::types::Address; @@ -399,6 +400,10 @@ pub enum PaymentCommands { #[structopt(flatten)] close_deposit_options: CloseDepositOptions, }, + TerminateDeposit { + #[structopt(flatten)] + terminate_deposit_options: TerminateDepositOptions, + }, CheckDeposit { #[structopt(flatten)] check_deposit_options: CheckDepositOptions,