Add check-expired-invoice command
This commit is contained in:
parent
109168b5eb
commit
fde8309bb9
9 changed files with 115 additions and 13 deletions
|
@ -85,3 +85,9 @@ Create Monero wallet:
|
|||
```shell
|
||||
mitractl create-monero-wallet "mitra-wallet" "passw0rd"
|
||||
```
|
||||
|
||||
Check expired invoice:
|
||||
|
||||
```shell
|
||||
mitractl check-expired-invoice 0184b062-d8d5-cbf1-a71b-6d1aafbae2ab
|
||||
```
|
||||
|
|
|
@ -36,6 +36,7 @@ async fn main() {
|
|||
SubCommand::UpdateCurrentBlock(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::ResetSubscriptions(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::CreateMoneroWallet(cmd) => cmd.execute(&config).await.unwrap(),
|
||||
SubCommand::CheckExpiredInvoice(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
_ => panic!(),
|
||||
};
|
||||
},
|
||||
|
|
30
src/cli.rs
30
src/cli.rs
|
@ -29,7 +29,10 @@ use crate::models::users::queries::{
|
|||
get_user_by_id,
|
||||
set_user_password,
|
||||
};
|
||||
use crate::monero::wallet::create_monero_wallet;
|
||||
use crate::monero::{
|
||||
helpers::check_expired_invoice,
|
||||
wallet::create_monero_wallet,
|
||||
};
|
||||
use crate::utils::{
|
||||
crypto_rsa::{
|
||||
generate_rsa_key,
|
||||
|
@ -64,6 +67,7 @@ pub enum SubCommand {
|
|||
UpdateCurrentBlock(UpdateCurrentBlock),
|
||||
ResetSubscriptions(ResetSubscriptions),
|
||||
CreateMoneroWallet(CreateMoneroWallet),
|
||||
CheckExpiredInvoice(CheckExpiredInvoice),
|
||||
}
|
||||
|
||||
/// Generate RSA private key
|
||||
|
@ -404,3 +408,27 @@ impl CreateMoneroWallet {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Check expired invoice
|
||||
#[derive(Parser)]
|
||||
pub struct CheckExpiredInvoice {
|
||||
id: Uuid,
|
||||
}
|
||||
|
||||
impl CheckExpiredInvoice {
|
||||
pub async fn execute(
|
||||
&self,
|
||||
config: &Config,
|
||||
db_client: &impl GenericClient,
|
||||
) -> Result<(), Error> {
|
||||
let monero_config = config.blockchain()
|
||||
.and_then(|conf| conf.monero_config())
|
||||
.ok_or(anyhow!("monero configuration not found"))?;
|
||||
check_expired_invoice(
|
||||
monero_config,
|
||||
db_client,
|
||||
&self.id,
|
||||
).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,6 +156,6 @@ mod tests {
|
|||
assert_eq!(invoice.chain_id, chain_id);
|
||||
assert_eq!(invoice.payment_address, payment_address);
|
||||
assert_eq!(invoice.amount, amount);
|
||||
assert!(matches!(invoice.invoice_status, InvoiceStatus::Open));
|
||||
assert_eq!(invoice.invoice_status, InvoiceStatus::Open);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::database::int_enum::{int_enum_from_sql, int_enum_to_sql};
|
|||
use crate::errors::ConversionError;
|
||||
use crate::utils::caip2::ChainId;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum InvoiceStatus {
|
||||
Open,
|
||||
Paid,
|
||||
|
|
59
src/monero/helpers.rs
Normal file
59
src/monero/helpers.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use monero_rpc::TransferType;
|
||||
use monero_rpc::monero::Address;
|
||||
use tokio_postgres::GenericClient;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::config::MoneroConfig;
|
||||
use crate::models::{
|
||||
invoices::queries::{
|
||||
get_invoice_by_id,
|
||||
set_invoice_status,
|
||||
},
|
||||
invoices::types::InvoiceStatus,
|
||||
};
|
||||
use super::wallet::{
|
||||
open_monero_wallet,
|
||||
DEFAULT_ACCOUNT,
|
||||
MoneroError,
|
||||
};
|
||||
|
||||
pub async fn check_expired_invoice(
|
||||
config: &MoneroConfig,
|
||||
db_client: &impl GenericClient,
|
||||
invoice_id: &Uuid,
|
||||
) -> Result<(), MoneroError> {
|
||||
let wallet_client = open_monero_wallet(config).await?;
|
||||
let invoice = get_invoice_by_id(db_client, invoice_id).await?;
|
||||
if invoice.chain_id != config.chain_id ||
|
||||
invoice.invoice_status != InvoiceStatus::Timeout
|
||||
{
|
||||
return Err(MoneroError::OtherError("can't process invoice"));
|
||||
};
|
||||
let address = Address::from_str(&invoice.payment_address)?;
|
||||
let address_index = wallet_client.get_address_index(address).await?;
|
||||
let transfers = wallet_client.incoming_transfers(
|
||||
TransferType::Available,
|
||||
Some(DEFAULT_ACCOUNT),
|
||||
Some(vec![address_index.minor]),
|
||||
).await?
|
||||
.transfers
|
||||
.unwrap_or_default();
|
||||
if transfers.is_empty() {
|
||||
log::info!("no incoming transfers");
|
||||
} else {
|
||||
for transfer in transfers {
|
||||
if transfer.subaddr_index != address_index {
|
||||
return Err(MoneroError::WalletRpcError("unexpected transfer"));
|
||||
};
|
||||
log::info!(
|
||||
"received payment for invoice {}: {}",
|
||||
invoice.id,
|
||||
transfer.amount,
|
||||
);
|
||||
};
|
||||
set_invoice_status(db_client, &invoice.id, InvoiceStatus::Paid).await?;
|
||||
};
|
||||
Ok(())
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub mod helpers;
|
||||
pub mod subscriptions;
|
||||
pub mod wallet;
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::convert::TryInto;
|
|||
use std::str::FromStr;
|
||||
|
||||
use chrono::{Duration, Utc};
|
||||
use monero_rpc::{RpcClient, TransferType};
|
||||
use monero_rpc::TransferType;
|
||||
use monero_rpc::monero::{Address, Amount};
|
||||
|
||||
use crate::config::{Instance, MoneroConfig};
|
||||
|
@ -28,6 +28,7 @@ use crate::models::{
|
|||
use super::wallet::{
|
||||
get_single_item,
|
||||
get_subaddress_balance,
|
||||
open_monero_wallet,
|
||||
send_monero,
|
||||
DEFAULT_ACCOUNT,
|
||||
MoneroError,
|
||||
|
@ -41,12 +42,7 @@ pub async fn check_monero_subscriptions(
|
|||
db_pool: &Pool,
|
||||
) -> Result<(), MoneroError> {
|
||||
let db_client = &mut **get_database_client(db_pool).await?;
|
||||
|
||||
let wallet_client = RpcClient::new(config.wallet_url.clone()).wallet();
|
||||
wallet_client.open_wallet(
|
||||
config.wallet_name.clone(),
|
||||
config.wallet_password.clone(),
|
||||
).await?;
|
||||
let wallet_client = open_monero_wallet(config).await?;
|
||||
|
||||
// Invoices waiting for payment
|
||||
let mut address_waitlist = vec![];
|
||||
|
@ -98,7 +94,11 @@ pub async fn check_monero_subscriptions(
|
|||
invoice.id,
|
||||
transfer.amount,
|
||||
);
|
||||
set_invoice_status(db_client, &invoice.id, InvoiceStatus::Paid).await?;
|
||||
if invoice.invoice_status == InvoiceStatus::Open {
|
||||
set_invoice_status(db_client, &invoice.id, InvoiceStatus::Paid).await?;
|
||||
} else {
|
||||
log::warn!("invoice has already been paid");
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -48,14 +48,21 @@ pub async fn create_monero_wallet(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_monero_address(
|
||||
pub async fn open_monero_wallet(
|
||||
config: &MoneroConfig,
|
||||
) -> Result<Address, MoneroError> {
|
||||
) -> Result<WalletClient, MoneroError> {
|
||||
let wallet_client = RpcClient::new(config.wallet_url.clone()).wallet();
|
||||
wallet_client.open_wallet(
|
||||
config.wallet_name.clone(),
|
||||
config.wallet_password.clone(),
|
||||
).await?;
|
||||
Ok(wallet_client)
|
||||
}
|
||||
|
||||
pub async fn create_monero_address(
|
||||
config: &MoneroConfig,
|
||||
) -> Result<Address, MoneroError> {
|
||||
let wallet_client = open_monero_wallet(config).await?;
|
||||
let (address, address_index) =
|
||||
wallet_client.create_address(DEFAULT_ACCOUNT, None).await?;
|
||||
log::info!("created monero address {}/{}", DEFAULT_ACCOUNT, address_index);
|
||||
|
|
Loading…
Reference in a new issue