use inquire::validator::Validation;
use serde_json::json;
use serde_json::Value;
use solana_sdk::{pubkey::Pubkey, transaction::VersionedTransaction};
use std::str::FromStr;
pub(crate) fn validate_json_compliance(json: &Value) -> bool {
let has_name = json.get("name").is_some();
let has_symbol = json.get("symbol").is_some();
let has_description = json.get("description").is_some();
let has_image = json.get("image").is_some();
let has_animation_url = json.get("animation_url").is_some();
let has_external_url = json.get("external_url").is_some();
let has_attributes = json.get("attributes").is_some();
has_name
& has_symbol
& has_description
& has_image
& has_animation_url
& has_external_url
& has_attributes
}
pub(crate) async fn swap_sol_for_shdw_tx(
shades: u64,
user: Pubkey,
) -> anyhow::Result<VersionedTransaction> {
let Ok(quote) = Value::from_str("e_sol_to_shdw(shades).await?) else {
return Err(anyhow::Error::msg("Failed to parse jup.ag quote response as json"))
};
let request_body = json!({
"route": dbg!("e[0]),
"userPublicKey": user.to_string(),
"wrapUnwrapSOL": true,
});
let client = reqwest::Client::new();
let response = client
.post("https://quote-api.jup.ag/v4/swap")
.header("Content-Type", "application/json")
.json(&request_body)
.send()
.await?;
let Ok(body) = serde_json::Value::from_str(&response.text().await?) else {
return Err(anyhow::Error::msg("Failed to parse jup.ag swap_tx response as json"))
};
let Some(Some(tx_body))= body.get("swapTransaction").map(|b| b.as_str()) else {
return Err(anyhow::Error::msg("Unexpected response from jup.ag swap_tx endpoint"))
};
#[allow(deprecated)]
let Ok(Ok(transaction)) = base64::decode(tx_body).map(|bytes| bincode::deserialize(&bytes)) else {
return Err(anyhow::Error::msg("Invalid base64 encoding from jup.ag swap_tx endpoint"))
};
Ok(transaction)
}
pub(crate) const SHDW_MINT: &'static str = "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y";
pub(crate) const SOL_MINT: &'static str = "So11111111111111111111111111111111111111112";
pub(crate) const SHDW_MINT_PUBKEY: Pubkey = Pubkey::new_from_array([
6, 121, 219, 1, 206, 42, 132, 247, 28, 19, 158, 124, 153, 66, 246, 218, 59, 51, 31, 222, 195,
49, 157, 2, 248, 153, 235, 167, 1, 52, 115, 126,
]);
async fn quote_sol_to_shdw(shades: u64) -> anyhow::Result<String> {
const SLIPPAGE_BPS: u16 = 5;
let url = format!(
"https://quote-api.jup.ag/v4/quote?inputMint={}&outputMint={}&amount={}&slippageBps={SLIPPAGE_BPS}&swapMode=ExactOut",
SOL_MINT, SHDW_MINT, shades
);
let response = reqwest::Client::new()
.get(&url)
.header("accept", "application/json")
.send()
.await?;
let body = response.text().await?;
Ok(body)
}
pub(crate) fn pubkey_validator(
input: &str,
) -> Result<Validation, Box<dyn std::error::Error + Send + Sync>> {
if Pubkey::from_str(input).is_ok() {
Ok(Validation::Valid)
} else {
Ok(Validation::Invalid("Invalid Pubkey".into()))
}
}
pub(crate) fn validate_and_convert_to_half_percent(input: &str) -> Result<u8, &'static str> {
let input = input.trim().trim_end_matches('%');
let value = input.parse::<f64>();
match value {
Ok(v) => {
if v < 0.0 {
Err("Value must be positive.")
} else if (2.0 * v).fract() != 0.0 {
Err("Value must be a whole or half number.")
} else {
Ok((2.0 * v).round() as u8)
}
}
Err(_) => Err("Invalid input, not a number."),
}
}
#[test]
fn test_validate_and_convert_to_half_percent() {
assert_eq!(validate_and_convert_to_half_percent("1"), Ok(2));
assert_eq!(validate_and_convert_to_half_percent("1%"), Ok(2));
assert_eq!(validate_and_convert_to_half_percent("1.5"), Ok(3));
assert_eq!(validate_and_convert_to_half_percent("1.5%"), Ok(3));
assert_eq!(validate_and_convert_to_half_percent("2"), Ok(4));
assert_eq!(validate_and_convert_to_half_percent("2%"), Ok(4));
assert_eq!(validate_and_convert_to_half_percent("2.0"), Ok(4));
assert_eq!(validate_and_convert_to_half_percent("2.0%"), Ok(4));
assert_eq!(validate_and_convert_to_half_percent("2.5"), Ok(5));
assert_eq!(validate_and_convert_to_half_percent("2.5%"), Ok(5));
assert_eq!(
validate_and_convert_to_half_percent("2.4"),
Err("Value must be a whole or half number.")
);
assert_eq!(
validate_and_convert_to_half_percent("-1"),
Err("Value must be positive.")
);
assert_eq!(
validate_and_convert_to_half_percent("-1.5"),
Err("Value must be positive.")
);
assert_eq!(
validate_and_convert_to_half_percent("not a number"),
Err("Invalid input, not a number.")
);
assert_eq!(
validate_and_convert_to_half_percent(""),
Err("Invalid input, not a number.")
);
}