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

fix: panic if no response from api & detect the right erc20 contract #55

Merged
merged 4 commits into from
Mar 27, 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
55 changes: 38 additions & 17 deletions bot/src/bot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::models::{AggregateResult, AggregateResults, DomainAggregateResult, Me
use crate::pipelines::{get_auto_renewal_altcoins_data, get_auto_renewal_data};
use crate::starknet_utils::check_pending_transactions;
use crate::starknetid_utils::{get_altcoin_quote, get_balances, get_renewal_price_eth};
use crate::utils::to_hex;
use crate::utils::{from_uint256, hex_to_bigdecimal, to_uint256};
use crate::{config::Config, models::AppState};

Expand Down Expand Up @@ -66,7 +67,18 @@ pub async fn get_domains_ready_for_renewal(
// Fetch balances for all renewers
let renewer_and_erc20: Vec<(String, String)> = results
.iter()
.map(|result| (result.renewer_address.clone(), result.erc20_addr.clone()))
.map(|result| {
(
result.renewer_address.clone(),
// get the erc20 address for the given auto_renew_contract
to_hex(
*config
.altcoins_mapping
.get(&result.auto_renew_contract)
.unwrap(),
),
)
})
.collect();

let balances = get_balances(config, renewer_and_erc20.clone()).await;
Expand All @@ -85,9 +97,7 @@ pub async fn get_domains_ready_for_renewal(
balances_iter.next().expect("Expected high not found"),
);
let mut outer_map = dynamic_balances.lock().unwrap();
let inner_map = outer_map
.entry(address.clone())
.or_default();
let inner_map = outer_map.entry(address.clone()).or_default();
inner_map.insert(erc20.clone(), balance);
}

Expand All @@ -111,16 +121,18 @@ pub async fn get_domains_ready_for_renewal(
if FieldElement::from_hex_be(erc20).unwrap() == config.contract.erc20 {
renewal_price_eth
} else {
match get_altcoin_quote(config, result.erc20_addr.clone()).await {
match get_altcoin_quote(config, erc20.to_string()).await {
Ok(quote) => {
(quote * renewal_price_eth)
/ BigInt::from_str("1000000000000000000").unwrap()
}
Err(e) => {
println!("Error while fetching quote: {:?}", e);
// this case can happen if the quote is not in the right range
// we return 0 and won't renew this domain
BigInt::from(0)
// in case get_altcoin_quote endpoint returns an error we panic with the error
logger.severe(format!(
"Error while fetching quote on starknetid server: {:?}",
e
));
panic!("Error while fetching quote on starknetid server: {:?}", e)
}
}
};
Expand All @@ -130,6 +142,7 @@ pub async fn get_domains_ready_for_renewal(
logger,
BigDecimal::from(balance.to_owned()),
BigDecimal::from(renewal_price.to_owned()),
erc20.clone(),
)
.await;

Expand All @@ -138,7 +151,7 @@ pub async fn get_domains_ready_for_renewal(
dynamic_balances
.lock()
.unwrap()
.entry(result.erc20_addr)
.entry(erc20.to_string())
.or_default()
.insert(address.to_owned(), new_balance);
};
Expand Down Expand Up @@ -186,25 +199,27 @@ async fn process_aggregate_result(
_logger: &Logger,
balance: BigDecimal,
renewal_price: BigDecimal,
erc20_addr: String,
) -> Option<AggregateResult> {
// Skip the rest if auto-renewal is not enabled
if !result.enabled || result.allowance.is_none() {
return None;
}

let renewer_addr = FieldElement::from_hex_be(&result.renewer_address).unwrap();
let erc20_allowance = if let Some(approval_value) = result.approval_value {
// map the vec of approval_values to get tha approval_value for the erc20_addr selected
let erc20_allowance = if let Some(approval_value) = result
.approval_values
.iter()
.find(|&data| data.erc20_addr == erc20_addr)
.map(|data| data.approval_value.clone())
{
hex_to_bigdecimal(&approval_value).unwrap()
} else {
BigDecimal::from(0)
};
let allowance = hex_to_bigdecimal(&result.allowance.unwrap()).unwrap();

// if renewal_price is 0, we don't renew the domain
if renewal_price == BigDecimal::from(0) {
return None;
}

// Check user meta hash
let mut tax_price = BigDecimal::from(0);
let mut meta_hash = FieldElement::ZERO;
Expand Down Expand Up @@ -466,7 +481,13 @@ pub async fn send_transaction(
.fee_estimate_multiplier(5.0f64);

match execution.estimate_fee().await {
Ok(fee) => match execution.nonce(nonce).max_fee(fee.overall_fee).send().await {
Ok(_) => match execution
.nonce(nonce)
// harcode max fee to 10$ = 0.0028 ETH
.max_fee(FieldElement::from(2800000000000000_u64))
.send()
.await
{
Ok(tx_result) => Ok(tx_result.transaction_hash),
Err(e) => {
let error_message = format!("An error occurred while renewing domains: {}", e);
Expand Down
65 changes: 63 additions & 2 deletions bot/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use serde::de::MapAccess;
use serde::de::Visitor;
use serde::Deserialize;
use serde::Deserializer;
use starknet::core::types::FieldElement;
use std::collections::HashMap;
use std::env;
use std::fmt;
use std::fs;

macro_rules! pub_struct {
Expand Down Expand Up @@ -65,17 +70,73 @@ pub_struct!(Clone, Deserialize; Server {
starknetid_api: String,
});

pub_struct!(Clone, Deserialize; Config {
pub_struct!(Clone, Deserialize; Altcoin {
address: FieldElement,
renewal_contract: FieldElement,
});

pub_struct!(Clone; Config {
contract: Contract,
database: Database,
account: MyAccount,
renewals : Renewals,
renewals: Renewals,
indexer_server: IndexerServer,
rpc: Rpc,
watchtower: Watchtower,
server: Server,
altcoins_mapping: HashMap<FieldElement, FieldElement>,
});

impl<'de> Deserialize<'de> for Config {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct OuterConfig {
contract: Contract,
database: Database,
account: MyAccount,
renewals: Renewals,
indexer_server: IndexerServer,
rpc: Rpc,
watchtower: Watchtower,
server: Server,
altcoins: HashMap<String, Altcoin>,
}

let OuterConfig {
contract,
database,
account,
renewals,
indexer_server,
rpc,
watchtower,
server,
altcoins,
} = OuterConfig::deserialize(deserializer)?;

// Build atcoins mapping
let altcoins_mapping = altcoins
.into_values()
.map(|val| (val.renewal_contract, val.address))
.collect();

Ok(Config {
contract,
database,
account,
renewals,
indexer_server,
rpc,
watchtower,
server,
altcoins_mapping,
})
}
}

pub fn load() -> Config {
let args: Vec<String> = env::args().collect();
let config_path = if args.len() <= 1 {
Expand Down
9 changes: 7 additions & 2 deletions bot/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,24 @@ pub struct Cursor {
pub from: Option<i64>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AutoRenewAllowance {
pub approval_value: String,
pub erc20_addr: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DomainAggregateResult {
pub domain: String,
pub expiry: Option<i32>,
pub renewer_address: String,
pub enabled: bool,
pub approval_value: Option<String>,
pub allowance: Option<String>,
pub last_renewal: Option<i64>,
pub meta_hash: Option<String>,
pub _cursor: Cursor,
pub erc20_addr: String,
pub auto_renew_contract: FieldElement,
pub approval_values: Vec<AutoRenewAllowance>,
}

pub struct AggregateResult {
Expand Down
25 changes: 16 additions & 9 deletions bot/src/pipelines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,35 +58,37 @@ pub async fn get_auto_renewal_data(
}},
doc! { "$unwind": { "path": "$approval_info", "preserveNullAndEmptyArrays": true } },
doc! { "$addFields": {
"erc20_addr": erc20_addr,
"auto_renew_contract": auto_renew_contract,
}},
doc! { "$group": {
"_id": "$domain_info.domain",
"expiry": { "$first": "$domain_info.expiry" },
"renewer_address": { "$first": "$renewer_address" },
"enabled": { "$first": "$enabled" },
"approval_value": { "$first": { "$ifNull": [ "$approval_info.allowance", "0x0" ] } },
"allowance": { "$first": "$allowance" },
"last_renewal": { "$first": "$last_renewal" },
"meta_hash": { "$first": "$meta_hash" },
"_cursor": { "$first": "$_cursor" },
"erc20_addr": { "$first": "$erc20_addr" },
"auto_renew_contract": { "$first": "$auto_renew_contract" },
"approval_values": {
"$push": {
"approval_value": "$approval_info.allowance",
"erc20_addr": erc20_addr
}
},
}},
doc! { "$project": {
"_id": 0,
"domain": "$_id",
"expiry": 1,
"renewer_address": 1,
"enabled": 1,
"approval_value": 1,
"allowance": 1,
"last_renewal": 1,
"meta_hash": 1,
"_cursor": 1,
"erc20_addr": 1,
"auto_renew_contract": 1,
"approval_values": 1,
}},
];

Expand Down Expand Up @@ -154,27 +156,30 @@ pub async fn get_auto_renewal_altcoins_data(
"expiry": { "$first": "$domain_info.expiry" },
"renewer_address": { "$first": "$renewer_address" },
"enabled": { "$first": "$enabled" },
"approval_value": { "$first": { "$ifNull": [ "$approval_info.allowance", "0x0" ] } },
"allowance": { "$first": "$allowance" },
"last_renewal": { "$first": "$last_renewal" },
"meta_hash": { "$first": "$meta_hash" },
"_cursor": { "$first": "$_cursor" },
"erc20_addr": { "$first": "$approval_info.erc20_addr" },
"auto_renew_contract": { "$first": "$auto_renew_contract" },
"approval_values": {
"$push": {
"approval_value": "$approval_info.allowance",
"erc20_addr": "$approval_info.erc20_addr"
}
},
}},
doc! { "$project": {
"_id": 0,
"domain": "$_id",
"expiry": 1,
"renewer_address": 1,
"enabled": 1,
"approval_value": 1,
"allowance": 1,
"last_renewal": 1,
"meta_hash": 1,
"_cursor": 1,
"erc20_addr": 1,
"auto_renew_contract": 1,
"approval_values": 1,
}},
];

Expand All @@ -190,5 +195,7 @@ pub async fn get_auto_renewal_altcoins_data(
// Check if the conversion was successful
let results = results?;

println!("results: {:?}", results);

Ok(results)
}
8 changes: 3 additions & 5 deletions bot/src/starknetid_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crate::{config::Config, starknet_utils::create_jsonrpc_client};
lazy_static::lazy_static! {
static ref PRICE_DOMAIN_LEN_1: BigInt = BigInt::from_u128(1068493150684932 * 365).unwrap();
static ref PRICE_DOMAIN_LEN_2: BigInt = BigInt::from_u128(657534246575343 * 365).unwrap();
static ref PRICE_DOMAIN_LEN_3: BigInt = BigInt::from_u128(410958904109590 * 365).unwrap();
static ref PRICE_DOMAIN_LEN_4: BigInt = BigInt::from_u128(232876712328767 * 365).unwrap();
static ref PRICE_DOMAIN_LEN_3: BigInt = BigInt::from_u128(200000000000000 * 365).unwrap();
static ref PRICE_DOMAIN_LEN_4: BigInt = BigInt::from_u128(73972602739726 * 365).unwrap();
static ref PRICE_DOMAIN: BigInt = BigInt::from_u128(24657534246575 * 365).unwrap();
}

Expand Down Expand Up @@ -49,9 +49,7 @@ pub async fn get_altcoin_quote(config: &Config, erc20: String) -> Result<BigInt>
match client.get(&url).send().await {
Ok(response) => match response.text().await {
Ok(text) => match serde_json::from_str::<QuoteQueryResult>(&text) {
Ok(results) => {
Ok(BigInt::from_str(&results.quote).unwrap())
}
Ok(results) => Ok(BigInt::from_str(&results.quote).unwrap()),
Err(err) => Err(anyhow!("Error parsing response: {:?}", err)),
},
Err(err) => Err(anyhow!("Error fetching response: {:?}", err)),
Expand Down
9 changes: 9 additions & 0 deletions config.template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,12 @@ rpc_url = "https://starknet-goerli.g.alchemy.com/v2/xxxxxxx"

[server]
starknetid_api = "https://api.starknet.id"

[altcoins]
[altcoins.ETH]
address = "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"
renewal_contract = "0x020379Ba14750ECEE8dde204D0649808BCf6D32E9fDe81Ca952Ab0360cdC0937"

[altcoins.STRK]
address = "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d"
renewal_contract = "0x078F63fcD145Ddc6ca932E562b466AFbfD7c9E882C9aa70f3e5b2ce05cD892eA"
Loading