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

feat: add altcoin renewal support #53

Merged
merged 1 commit into from
Mar 13, 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
328 changes: 119 additions & 209 deletions bot/src/bot.rs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions bot/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ pub_struct!(Clone, Deserialize; WatchtowerTypes {
severe: String,
});

pub_struct!(Clone, Deserialize; Server {
starknetid_api: String,
});

pub_struct!(Clone, Deserialize; Config {
contract: Contract,
database: Database,
Expand All @@ -68,6 +72,7 @@ pub_struct!(Clone, Deserialize; Config {
indexer_server: IndexerServer,
rpc: Rpc,
watchtower: Watchtower,
server: Server,
});

pub fn load() -> Config {
Expand Down
49 changes: 25 additions & 24 deletions bot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use starknet::{
providers::Provider,
signers::{LocalWallet, SigningKey},
};
use starknet_id::decode;
use starknet_utils::create_jsonrpc_client;
use tokio::time::sleep;

Expand All @@ -23,6 +22,7 @@ mod bot;
mod config;
mod logger;
mod models;
mod pipelines;
mod sales_tax;
mod starknet_utils;
mod starknetid_utils;
Expand Down Expand Up @@ -161,30 +161,31 @@ async fn main() {
println!("[bot] Checking domains to renew");
match bot::get_domains_ready_for_renewal(&conf, &shared_state, &logger).await {
Ok(aggregate_results) => {
//println!("[bot] checking domains to renew today");
if !aggregate_results.domains.is_empty() {
match renew_domains(&conf, &account, aggregate_results.clone(), &logger)
if !aggregate_results.is_empty() {
for (auto_renew_contract, result) in &aggregate_results {
match renew_domains(
&conf,
&account,
result.clone(),
auto_renew_contract,
&logger,
)
.await
{
Ok(_) => {
aggregate_results
.domains
.iter()
.zip(aggregate_results.renewers.iter())
.for_each(|(d, r)| {
logger.info(format!(
"- `Renewal: {}` by `{:#x}`",
&decode(*d),
r
))
});
}
Err(e) => {
logger.severe(format!("Unable to renew domains: {}", e));
if e.to_string().contains("request rate limited") {
continue;
} else {
break;
{
Ok(_) => {
logger.info(format!(
"`Renewed {} domains on auto renewal contract address {}",
result.domains.len(),
auto_renew_contract
));
}
Err(e) => {
logger.severe(format!("Unable to renew domains: {}", e));
if e.to_string().contains("request rate limited") {
continue;
} else {
break;
}
}
}
}
Expand Down
62 changes: 6 additions & 56 deletions bot/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bigdecimal::BigDecimal;
use bson::DateTime;
use mongodb::Database;
use serde::{Deserialize, Serialize};
use starknet::core::types::{FieldElement, TransactionExecutionStatus};
use starknet::core::types::FieldElement;

pub struct AppState {
pub db: Database,
Expand All @@ -19,6 +19,7 @@ pub struct Domain {
pub token_id: Option<String>,
pub creation_date: Option<DateTime>,
pub rev_addr: Option<String>,
pub auto_renew_contract: Option<String>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -51,6 +52,8 @@ pub struct DomainAggregateResult {
pub last_renewal: Option<i64>,
pub meta_hash: Option<String>,
pub _cursor: Cursor,
pub erc20_addr: String,
pub auto_renew_contract: FieldElement,
}

pub struct AggregateResult {
Expand All @@ -59,6 +62,7 @@ pub struct AggregateResult {
pub domain_price: BigDecimal,
pub tax_price: BigDecimal,
pub meta_hash: FieldElement,
pub auto_renew_contract: FieldElement,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand All @@ -68,6 +72,7 @@ pub struct AggregateResults {
pub domain_prices: Vec<BigDecimal>,
pub tax_prices: Vec<BigDecimal>,
pub meta_hashes: Vec<FieldElement>,
pub auto_renew_contracts: Vec<FieldElement>,
}

#[derive(Serialize, Deserialize, Debug)]
Expand Down Expand Up @@ -97,58 +102,3 @@ pub struct TxResult {
pub revert_reason: Option<String>,
pub domains_renewed: usize,
}

pub trait Unzip5 {
type A;
type B;
type C;
type D;
type E;

fn unzip5(
self,
) -> (
Vec<Self::A>,
Vec<Self::B>,
Vec<Self::C>,
Vec<Self::D>,
Vec<Self::E>,
);
}

impl<T, A, B, C, D, E> Unzip5 for T
where
T: Iterator<Item = (A, B, C, D, E)>,
{
type A = A;
type B = B;
type C = C;
type D = D;
type E = E;

fn unzip5(
self,
) -> (
Vec<Self::A>,
Vec<Self::B>,
Vec<Self::C>,
Vec<Self::D>,
Vec<Self::E>,
) {
let mut a = Vec::new();
let mut b = Vec::new();
let mut c = Vec::new();
let mut d = Vec::new();
let mut e = Vec::new();

for (x, y, z, w, v) in self {
a.push(x);
b.push(y);
c.push(z);
d.push(w);
e.push(v);
}

(a, b, c, d, e)
}
}
194 changes: 194 additions & 0 deletions bot/src/pipelines.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
use anyhow::Result;
use bson::{doc, Bson};
use chrono::{Duration, Utc};
use futures::TryStreamExt;
use starknet::core::types::FieldElement;
use std::sync::Arc;

use crate::{
config::Config,
models::{AppState, Domain, DomainAggregateResult},
utils::to_hex,
};

pub async fn get_auto_renewal_data(
config: &Config,
state: &Arc<AppState>,
) -> Result<Vec<DomainAggregateResult>> {
let auto_renews_collection = state.db.collection::<Domain>("auto_renew_flows");
let min_expiry_date = Utc::now() + Duration::days(400);
let erc20_addr = to_hex(config.contract.erc20);
let auto_renew_contract = FieldElement::to_string(&config.contract.renewal);
println!("timestamp: {}", min_expiry_date.timestamp());
// Define aggregate pipeline
let pipeline = vec![
doc! { "$match": { "_cursor.to": null } },
doc! { "$match": { "enabled": true } },
doc! { "$lookup": {
"from": "domains",
"let": { "domain_name": "$domain" },
"pipeline": [
{ "$match":
{ "$expr":
{ "$and": [
{ "$eq": [ "$domain", "$$domain_name" ] },
{ "$eq": [ { "$ifNull": [ "$_cursor.to", null ] }, null ] },
]}
}
},
],
"as": "domain_info",
}},
doc! { "$unwind": "$domain_info" },
doc! { "$match": { "domain_info.expiry": { "$lt": Bson::Int64(min_expiry_date.timestamp()) } } },
doc! { "$lookup": {
"from": "auto_renew_approvals",
"let": { "renewer_addr": "$renewer_address" },
"pipeline": [
{ "$match":
{ "$expr":
{ "$and": [
{ "$eq": [ "$renewer", "$$renewer_addr" ] },
{ "$eq": [ { "$ifNull": [ "$_cursor.to", null ] }, null ] },
]}
}
}
],
"as": "approval_info",
}},
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" },
}},
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,
}},
];

// Execute the pipeline
let cursor = auto_renews_collection.aggregate(pipeline, None).await?;
// Extract the results as Vec<bson::Document>
let bson_docs: Vec<bson::Document> = cursor.try_collect().await?;
// Convert each bson::Document into DomainAggregateResult
let results: Result<Vec<DomainAggregateResult>, _> = bson_docs
.into_iter()
.map(|doc| bson::from_bson(bson::Bson::Document(doc)))
.collect();
// Check if the conversion was successful
let results = results?;

Ok(results)
}

pub async fn get_auto_renewal_altcoins_data(
config: &Config,
state: &Arc<AppState>,
) -> Result<Vec<DomainAggregateResult>> {
let auto_renews_collection = state.db.collection::<Domain>("auto_renew_flows_altcoins");
let min_expiry_date = Utc::now() + Duration::days(400); // todo : change to 30 days

// Define aggregate pipeline
let pipeline = vec![
doc! { "$match": { "_cursor.to": null } },
doc! { "$match": { "enabled": true } },
doc! { "$lookup": {
"from": "domains",
"let": { "domain_name": "$domain" },
"pipeline": [
{ "$match":
{ "$expr":
{ "$and": [
{ "$eq": [ "$domain", "$$domain_name" ] },
{ "$eq": [ { "$ifNull": [ "$_cursor.to", null ] }, null ] },
]}
}
},
],
"as": "domain_info",
}},
doc! { "$unwind": "$domain_info" },
doc! { "$match": { "domain_info.expiry": { "$lt": Bson::Int64(min_expiry_date.timestamp()) } } },
doc! { "$lookup": {
"from": "auto_renew_approvals_altcoins",
"let": { "renewer_addr": "$renewer_address" },
"pipeline": [
{ "$match":
{ "$expr":
{ "$and": [
{ "$eq": [ "$renewer", "$$renewer_addr" ] },
{ "$eq": [ { "$ifNull": [ "$_cursor.to", null ] }, null ] },
]}
}
}
],
"as": "approval_info",
}},
doc! { "$unwind": { "path": "$approval_info", "preserveNullAndEmptyArrays": true } },
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": "$approval_info.erc20_addr" },
"auto_renew_contract": { "$first": "$auto_renew_contract" },
}},
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,
}},
];

// Execute the pipeline
let cursor = auto_renews_collection.aggregate(pipeline, None).await?;
// Extract the results as Vec<bson::Document>
let bson_docs: Vec<bson::Document> = cursor.try_collect().await?;
// Convert each bson::Document into DomainAggregateResult
let results: Result<Vec<DomainAggregateResult>, _> = bson_docs
.into_iter()
.map(|doc| bson::from_bson(bson::Bson::Document(doc)))
.collect();
// Check if the conversion was successful
let results = results?;

Ok(results)
}
Loading
Loading