From ca3b427738708965d70c8f1139ae416f0f7fc6b8 Mon Sep 17 00:00:00 2001 From: ayushtom Date: Fri, 3 May 2024 18:52:45 +0530 Subject: [PATCH] feat: add claimable endpoint --- config.template.toml | 5 +- src/endpoints/quests/haiko/claimable.rs | 109 ++++++++++++++++++++++++ src/endpoints/quests/haiko/mod.rs | 3 +- src/endpoints/quests/uri.rs | 10 +++ 4 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 src/endpoints/quests/haiko/claimable.rs diff --git a/config.template.toml b/config.template.toml index b6480784..5150a4ff 100644 --- a/config.template.toml +++ b/config.template.toml @@ -1092,6 +1092,7 @@ options = [ correct_answers = [*] + [quizzes.haiko] name = "Strategist quiz" desc = "Take part in our Quiz to test your knowledge about Haiko, and you'll have a chance to win 100 USDC." @@ -1102,10 +1103,10 @@ kind = "text_choice" layout = "default" question = "What is Haiko?" options = [ - "An automated market making platform featuring custom strategies", "A lending protocol", "A stablecoin provider", "An online e-commerce site", + "An automated market making platform featuring custom strategies", ] correct_answers = [*] @@ -1114,9 +1115,9 @@ kind = "text_choice" layout = "default" question = "What key benefits to strategists offer?" options = [ - "Automatically rebalances positions so they keep earning yield", "Increases transaction fees", "Doubles my rewards from providing liquidity", + "Automatically rebalances positions so they keep earning yield", "Restricts me from withdrawing liquidity", ] correct_answers = [*] diff --git a/src/endpoints/quests/haiko/claimable.rs b/src/endpoints/quests/haiko/claimable.rs new file mode 100644 index 00000000..9a3d7a2b --- /dev/null +++ b/src/endpoints/quests/haiko/claimable.rs @@ -0,0 +1,109 @@ +use crate::models::{AppState, CompletedTaskDocument, Reward, RewardResponse}; +use crate::utils::{get_error, get_nft}; +use axum::{ + extract::{Query, State}, + http::StatusCode, + response::IntoResponse, + Json, +}; +use axum_auto_routes::route; +use futures::StreamExt; +use mongodb::bson::doc; +use serde::Deserialize; +use starknet::{ + core::types::FieldElement, + signers::{LocalWallet, SigningKey}, +}; +use std::sync::Arc; + +const QUEST_ID: u32 = 29; +const TASK_IDS: &[u32] = &[140, 141, 142, 143, 144]; +const LAST_TASK: u32 = TASK_IDS[4]; +const NFT_LEVEL: u32 = 41; + +#[derive(Deserialize)] +pub struct ClaimableQuery { + addr: FieldElement, +} + +#[route( +get, +"/quests/haiko/claimable", +crate::endpoints::quests::haiko::claimable +)] +pub async fn handler( + State(state): State>, + Query(query): Query, +) -> impl IntoResponse { + let collection = state + .db + .collection::("completed_tasks"); + + let pipeline = vec![ + doc! { + "$match": { + "address": &query.addr.to_string(), + "task_id": { "$in": TASK_IDS }, + }, + }, + doc! { + "$lookup": { + "from": "tasks", + "localField": "task_id", + "foreignField": "id", + "as": "task", + }, + }, + doc! { + "$match": { + "task.quest_id": QUEST_ID, + }, + }, + doc! { + "$group": { + "_id": "$address", + "completed_tasks": { "$push": "$task_id" }, + }, + }, + doc! { + "$match": { + "completed_tasks": { "$all": TASK_IDS }, + }, + }, + ]; + + let completed_tasks = collection.aggregate(pipeline, None).await; + match completed_tasks { + Ok(mut tasks_cursor) => { + if tasks_cursor.next().await.is_none() { + return get_error("User hasn't completed all tasks".into()); + } + + let signer = LocalWallet::from(SigningKey::from_secret_scalar( + state.conf.nft_contract.private_key, + )); + + let mut rewards = vec![]; + + let Ok((token_id, sig)) = + get_nft(QUEST_ID, LAST_TASK, &query.addr, NFT_LEVEL, &signer).await + else { + return get_error("Signature failed".into()); + }; + + rewards.push(Reward { + task_id: LAST_TASK, + nft_contract: state.conf.nft_contract.address.clone(), + token_id: token_id.to_string(), + sig: (sig.r, sig.s), + }); + + if rewards.is_empty() { + get_error("No rewards found for this user".into()) + } else { + (StatusCode::OK, Json(RewardResponse { rewards })).into_response() + } + } + Err(_) => get_error("Error querying rewards".into()), + } +} diff --git a/src/endpoints/quests/haiko/mod.rs b/src/endpoints/quests/haiko/mod.rs index ffa48626..2c5c4121 100644 --- a/src/endpoints/quests/haiko/mod.rs +++ b/src/endpoints/quests/haiko/mod.rs @@ -1,4 +1,5 @@ pub mod discord_fw_callback; pub mod verify_deposit; pub mod verify_twitter_fw; -pub mod verify_twitter_rw; \ No newline at end of file +pub mod verify_twitter_rw; +pub mod claimable; \ No newline at end of file diff --git a/src/endpoints/quests/uri.rs b/src/endpoints/quests/uri.rs index 4f40577c..e0f07d58 100644 --- a/src/endpoints/quests/uri.rs +++ b/src/endpoints/quests/uri.rs @@ -444,6 +444,16 @@ pub async fn handler( }), ).into_response(), + Some(41) => ( + StatusCode::OK, + Json(TokenURI { + name: "Haiko Strategist NFT ".into(), + description: "A Haiko Strategist NFT won for successfully finishing the Quest".into(), + image: format!("{}/haiko/haikoStrategist.webp", state.conf.variables.app_link), + attributes: None, + }), + ).into_response(), + _ => get_error("Error, this level is not correct".into()), }