Skip to content

Commit

Permalink
Merge branch 'master' into ayush/focustree-quest
Browse files Browse the repository at this point in the history
  • Loading branch information
ayushtom authored Nov 29, 2023
2 parents 0e0805d + 4056c4b commit 1c7fde6
Show file tree
Hide file tree
Showing 8 changed files with 429 additions and 19 deletions.
10 changes: 8 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ pub_struct!(Clone, Deserialize; Twitter {
oauth2_secret: String,
});

pub_struct!(Clone, Deserialize; QuestBoost{
private_key: FieldElement,
update_interval: u64,
});

pub_struct!(Clone, Deserialize; Discord {
oauth2_clientid: String,
oauth2_secret: String,
Expand All @@ -85,8 +90,8 @@ pub enum QuizQuestionType {

impl<'de> Deserialize<'de> for QuizQuestionType {
fn deserialize<D>(deserializer: D) -> Result<QuizQuestionType, D::Error>
where
D: Deserializer<'de>,
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.to_lowercase().as_str() {
Expand Down Expand Up @@ -144,6 +149,7 @@ pub_struct!(Clone, Deserialize; Config {
quizzes: HashMap<String, Quiz>,
starkscan: Starkscan,
achievements: Achievements,
quest_boost: QuestBoost,
});

pub fn load() -> Config {
Expand Down
106 changes: 106 additions & 0 deletions src/endpoints/has_completed_quest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use crate::{models::AppState, utils::get_error};
use axum::{
extract::{Query, State},
response::IntoResponse,
Json,
};

use futures::TryStreamExt;
use mongodb::bson::{doc, Document};
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
use starknet::core::types::FieldElement;
use std::sync::Arc;

#[derive(Debug, Serialize, Deserialize)]
pub struct HasCompletedQuestsQuery {
addr: FieldElement,
quest_id: u32,
}

pub async fn handler(
State(state): State<Arc<AppState>>,
Query(query): Query<HasCompletedQuestsQuery>,
) -> impl IntoResponse {
let address = query.addr.to_string();
let quest_id = query.quest_id;
let pipeline = vec![
doc! {
"$match": doc! {
"address": address,
}
},
doc! {
"$lookup": doc! {
"from": "tasks",
"localField": "task_id",
"foreignField": "id",
"as": "associatedTask"
}
},
doc! {
"$unwind": "$associatedTask"
},
doc! {
"$project": doc! {
"_id": 0,
"address": 1,
"task_id": 1,
"quest_id": "$associatedTask.quest_id"
}
},
doc! {
"$group": doc! {
"_id": "$quest_id",
"done": doc! {
"$sum": 1
}
}
},
doc! {
"$match": doc! {
"_id": quest_id,
}
},
doc! {
"$lookup": doc! {
"from": "tasks",
"localField": "_id",
"foreignField": "quest_id",
"as": "tasks"
}
},
doc! {
"$project": doc! {
"_id": 0,
"result": doc! {
"$cond": doc! {
"if": doc! {
"$eq": [
doc! {
"$size": "$tasks"
},
"$done"
]
},
"then": true,
"else": false
}
}
}
},
];
let tasks_collection = state.db.collection::<Document>("completed_tasks");
match tasks_collection.aggregate(pipeline, None).await {
Ok(cursor) => {
let mut cursor = cursor;
let mut result = false;
while let Some(doc) = cursor.try_next().await.unwrap() {
result = doc.get("result").unwrap().as_bool().unwrap();
}
let response = serde_json::json!({ "completed": result });
(StatusCode::OK, Json(response)).into_response()
}
Err(_) => get_error("Error querying status".to_string()),
}
}
2 changes: 2 additions & 0 deletions src/endpoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ pub mod get_tasks;
pub mod get_trending_quests;
pub mod quests;
pub mod leaderboard;
pub mod quest_boost;
pub mod has_completed_quest;
62 changes: 62 additions & 0 deletions src/endpoints/quest_boost/get_claim_params.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::{models::AppState, utils::get_error};
use axum::{
extract::{Query, State},
response::IntoResponse,
Json,
};
use std::str::FromStr;

use mongodb::bson::{doc, Document};
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
use serde_json::json;
use starknet::core::crypto::ecdsa_sign;
use starknet::core::{crypto::pedersen_hash, types::FieldElement};
use std::sync::Arc;

#[derive(Debug, Serialize, Deserialize)]
pub struct GetClaimBoostQuery {
boost_id: u32,
}

pub async fn handler(
State(state): State<Arc<AppState>>,
Query(query): Query<GetClaimBoostQuery>,
) -> impl IntoResponse {
let boost_id = query.boost_id;
let collection = state.db.collection::<Document>("boosts");
let res=collection.find_one(doc! {"id":boost_id},None).await.unwrap();

// if no boost found with the requested id
if res.is_none() {
return get_error(format!("Boost with id {} not found", boost_id));
}

let boost: Document = res.unwrap();
let amount = boost.get("amount").unwrap().as_i32().unwrap() as u32;
let token = boost.get("token").unwrap().as_str().unwrap();
let address = boost.get("winner").unwrap().as_str().unwrap();

let hashed = pedersen_hash(
&FieldElement::from(boost_id),
&pedersen_hash(
&FieldElement::from(amount),
&pedersen_hash(
&FieldElement::from(0 as u32),
&pedersen_hash(
&FieldElement::from_str(token).unwrap(),
&FieldElement::from_str(address).unwrap(),
),
),
),
);

match ecdsa_sign(&state.conf.quest_boost.private_key, &hashed) {
Ok(signature) => (
StatusCode::OK,
Json(json!({"address": address, "r": signature.r, "s": signature.s})),
)
.into_response(),
Err(e) => get_error(format!("Error while generating signature: {}", e)),
}
}
1 change: 1 addition & 0 deletions src/endpoints/quest_boost/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod get_claim_params;
12 changes: 11 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::net::SocketAddr;
use std::sync::Arc;

use tower_http::cors::{Any, CorsLayer};
use crate::utils::{add_leaderboard_table};
use crate::utils::{ add_leaderboard_table, run_boosts_raffle};

#[tokio::main]
async fn main() {
Expand Down Expand Up @@ -49,6 +49,8 @@ async fn main() {
println!("database: connected");
}

let db_instance = shared_state.db.clone();
run_boosts_raffle(&db_instance,conf.quest_boost.update_interval);
add_leaderboard_table(&shared_state.db).await;

let cors = CorsLayer::new().allow_headers(Any).allow_origin(Any);
Expand All @@ -66,6 +68,10 @@ async fn main() {
"/get_completed_quests",
get(endpoints::get_completed_quests::handler),
)
.route(
"/has_completed_quests",
get(endpoints::has_completed_quest::handler),
)
.route(
"/get_quest_participants",
get(endpoints::get_quest_participants::handler),
Expand Down Expand Up @@ -439,6 +445,10 @@ async fn main() {
"/leaderboard/get_ranking",
get(endpoints::leaderboard::get_ranking::handler),
)
.route(
"/boost/get_claim_params",
get(endpoints::quest_boost::get_claim_params::handler),
)
.with_state(shared_state)
.layer(cors);

Expand Down
13 changes: 13 additions & 0 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,19 @@ pub_struct!(Debug, Serialize, Deserialize; LeaderboardTable {
timestamp:f64,
});


pub_struct!(Debug, Serialize, Deserialize; BoostTable {
amount: i32,
token: String,
expiry: i64,
quests: Vec<i32>,
claimed: bool,
winner: Option<String>,
id: i32,
boost_description: String,
img_url: String,
});

pub_struct!(Debug, Serialize, Deserialize; NftBalance {
contract_address: String,
token_id: String,
Expand Down
Loading

0 comments on commit 1c7fde6

Please sign in to comment.