diff --git a/config.template.toml b/config.template.toml index 23be6d7f..becd8df1 100644 --- a/config.template.toml +++ b/config.template.toml @@ -448,4 +448,180 @@ options = [ "A browser extension for secure internet browsing.", "An online shopping platform for buying digital goods." ] -correct_answers = [*] \ No newline at end of file +correct_answers = [*] + +[quizzes.avnu] +name = "AVNU NoFluff Quiz" +desc = "Take part in our AVNU NoFluff Quiz to test your knowledge about Starknet’s Aggerator, and you'll have a chance to win an exclusive AVNU NoFluff Quiz as your reward." +intro = "Starknet Quest Quiz Rounds, a quiz series designed to make Starknet ecosystem knowledge accessible and enjoyable for all. Test your understanding of the workings of AVNU, enjoy the experience, and earn an exclusive NFT reward by testing your knowledge about Starknet Ecosystem projects!" + +[[quizzes.avnu.questions]] +kind = "text_choice" +layout = "default" +question = "What is AVNU's mission? " +options = [ + "To build Liquidity Infrastructure for traders and dApps", + "To offer the highest yields on investments", + "To create a social media platform", + "To provide health services " +] +correct_answers = [*] + +[[quizzes.avnu.questions]] +kind = "text_choice" +layout = "default" +question = "What problem does AVNU aim to address in the DeFi space?" +options = [ + "Inefficiencies in transportation systems", + "Poor weather forecasting", + "Capital inefficiency and poor price discovery in AMMs", + "Lack of social media engagement " +] +correct_answers = [*] + +[[quizzes.avnu.questions]] +kind = "text_choice" +layout = "default" +question = "How does AVNU's RFQ system work to improve the trading experience?" +options = [ + "By offering the highest possible yields to users", + "By preventing impermanent loss", + "By aggregating liquidity from various AMMs", + "By leveraging professional market makers and off-chain pricing algorithms to optimize pricing and minimize hidden costs" +] +correct_answers = [*] + +[[quizzes.avnu.questions]] +kind = "text_choice" +layout = "default" +question = "What is MEV protection, and how does AVNU's RFQ system provide it?" +options = [ + "MEV protection is Maximum Earnings Volatility, and AVNU ensures it through trading volume.", + "MEV protection is Market Efficiency Verification, and AVNU uses it to verify liquidity sources.", + "MEV protection is Miner Extractable Value, and AVNU uses cryptographic signatures to prevent front-running and maintain a secure trading environment.", + "MEV protection is Monetary Exchange Value, and AVNU guarantees it through blockchain technology. " +] +correct_answers = [*] + +[quizzes.zklend] +name = "ZkLend Zenders Quiz" +desc = "Take part in our ZkLend Zenders Quiz to test your DeFi knowledge, and you'll have a chance to win an exclusive ZkLend Zenders NFT as your reward." +intro = "Starknet Quest Quiz Rounds, a quiz series designed to make Starknet ecosystem knowledge accessible and enjoyable for all. Test your understanding of the intricate workings of ZkLend, enjoy the experience and earn exclusive NFT rewards by testing your Starknet-related topics." + +[[quizzes.zklend.questions]] +kind = "text_choice" +layout = "default" +question = "What is ZkLend?" +options = [ + "ZkLend is a traditional banking system.", + "ZkLend is a cryptocurrency used for online payments.", + "ZkLend is a permissionless lending market for retail users, offering depositing, borrowing, and earning yields on digital assets.", + "ZkLend is a physical lending institution with branches worldwide." +] +correct_answers = [*] + +[[quizzes.zklend.questions]] +kind = "text_choice" +layout = "default" +question = "What does borrowing and lending mean in the context of ZkLend?" +options = [ + "Borrowing allows users to deposit assets to earn interest, while lending involves borrowing assets using collateral.", + "Lending allows users to deposit assets to earn interest, while borrowing involves borrowing assets using collateral.", + "Borrowing and lending both refer to depositing assets to earn interest without any collateral involved.", + "Borrowing and lending are unrelated to ZKLend; it's a decentralized platform for gaming. " +] +correct_answers = [*] + +[[quizzes.zklend.questions]] +kind = "text_choice" +layout = "default" +question = "What is the Health Factor in ZkLend?" +options = [ + "A numerical representation of the leverage ratio", + "A metric showing a user's borrowing capacity", + "The sum of outstanding borrowings and accrued interest", + "The safety of deposited assets in relation to borrowed assets" +] +correct_answers = [*] + +[[quizzes.zklend.questions]] +kind = "text_choice" +layout = "default" +question = "What does liquidation mean in ZkLend?" +options = [ + "Liquidation is a process initiated by borrowers to lower their debt.", + "Liquidation is the process of selling off collateral to repay a portion of a borrower's debt when their Health Factor falls below 1.", + "Liquidation is a bonus given to borrowers who maintain a high Health Factor.", + "Liquidation is a penalty imposed on external parties for monitoring zkLend's loan portfolios." +] +correct_answers = [*] + +[quizzes.starknetid] +name = "Starknet ID Tribe Quiz" +desc = "Take part in our Starknet ID Tribe Quiz to test your knowledge, and you'll have a chance to win an exclusive Starknet ID Tribe NFT as your reward." +intro = "Starknet Quest Quiz Rounds, a quiz series designed to make Starknet ecosystem knowledge accessible and enjoyable for all. Test your understanding of the Basics of how Starknet ID functions, enjoy and earn an exclusive NFT reward by testing your knowledge about Starknet Ecosystem projects!" + +[[quizzes.starknetid.questions]] +kind = "text_choice" +layout = "default" +question = "What is the primary purpose of Starknet.id?" +options = [ + "A social media platform", + "An online marketplace", + "An identity and naming protocol for Starknet", + "A gaming platform" +] +correct_answers = [*] + +[[quizzes.starknetid.questions]] +kind = "text_choice" +layout = "default" +question = "What extension do the domain names use on Starknet.id?" +options = [ + ".com", + ".stark", + ".crypto", + ".eth" +] +correct_answers = [*] + +[[quizzes.starknetid.questions]] +kind = "text_choice" +layout = "default" +question = "What is the purpose of the 'Proof of Personhood' (POP) verification in Starknet.id?" +options = [ + "To verify financial transactions", + "To prove ownership of digital assets", + "To verify that a user is a real human and a single person", + "To confirm the user's location" +] +correct_answers = [*] + +[quizzes.sithswap] +name = "SithSwap The Dark Side Quiz" +desc = "Take part in our SithSwap The Dark Side Quiz to test your knowledge, and you'll have a chance to win an exclusive The Dark Side NFT as your reward." +intro = "Starknet Quest Quiz Rounds, a quiz series designed to make Starknet ecosystem knowledge accessible and enjoyable for all. Put your knowledge of the fundamental workings of SithSwap to the test, enjoy and earn an exclusive NFT reward by testing your knowledge about Starknet Ecosystem projects!" + +[[quizzes.sithswap.questions]] +kind = "text_choice" +layout = "default" +question = "What are volatile pairs in dual-liquidity pools?" +options = [ + "Volatile pairs are designed for assets with little-to-no volatility in trading correlation.", + "Volatile pairs rely on a constant-product formula.", + "Volatile pairs are optimized for assets with medium-to-high price volatility and use a generic constant-product formula.", + "Volatile pairs have extremely low slippage on large trading volumes." +] +correct_answers = [*] + +[[quizzes.sithswap.questions]] +kind = "text_choice" +layout = "default" +question = "Why are stable pairs attractive for traders?" +options = [ + "Because they offer high returns on investment", + "Because they involve tokens with unpredictable price fluctuations", + "Because they allow for extremely low slippage, even on large trading volumes", + "Because they have high liquidity and are easy to trade" +] +correct_answers = [*] diff --git a/src/endpoints/quests/avnu/claimable.rs b/src/endpoints/quests/avnu/claimable.rs index 0e8a7dfc..8cfba227 100644 --- a/src/endpoints/quests/avnu/claimable.rs +++ b/src/endpoints/quests/avnu/claimable.rs @@ -16,8 +16,8 @@ use starknet::{ use std::sync::Arc; const QUEST_ID: u32 = 3; -const TASK_IDS: &[u32] = &[12, 13]; -const LAST_TASK: u32 = TASK_IDS[1]; +const TASK_IDS: &[u32] = &[12, 13, 54]; +const LAST_TASK: u32 = TASK_IDS[2]; const NFT_LEVEL: u32 = 6; #[derive(Deserialize)] diff --git a/src/endpoints/quests/avnu/mod.rs b/src/endpoints/quests/avnu/mod.rs index 1c19b08c..c5158266 100644 --- a/src/endpoints/quests/avnu/mod.rs +++ b/src/endpoints/quests/avnu/mod.rs @@ -1,3 +1,4 @@ pub mod claimable; pub mod discord_fw_callback; +pub mod verify_quiz; pub mod verify_swap; diff --git a/src/endpoints/quests/avnu/verify_quiz.rs b/src/endpoints/quests/avnu/verify_quiz.rs new file mode 100644 index 00000000..599d8086 --- /dev/null +++ b/src/endpoints/quests/avnu/verify_quiz.rs @@ -0,0 +1,42 @@ +use std::sync::Arc; + +use crate::{ + common::verify_quiz::verify_quiz, + models::{AppState, VerifyQuizQuery}, + utils::{get_error, CompletedTasksTrait}, +}; +use axum::{extract::State, http::StatusCode, response::IntoResponse, Json}; +use serde_json::json; +use starknet::core::types::FieldElement; + +pub async fn handler( + State(state): State>, + body: Json, +) -> impl IntoResponse { + let task_id = 54; + if body.addr == FieldElement::ZERO { + return get_error("Please connect your wallet first".to_string()); + } + + let user_answers_numbers: Result>, _> = body + .user_answers_list + .iter() + .map(|inner_list| { + inner_list + .iter() + .map(|s| s.parse::()) + .collect::, _>>() + }) + .collect(); + + match user_answers_numbers { + Ok(responses) => match verify_quiz(&state.conf, body.addr, &body.quiz_name, &responses) { + true => match state.upsert_completed_task(body.addr, task_id).await { + Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), + Err(e) => get_error(format!("{}", e)), + }, + false => get_error("Incorrect answers".to_string()), + }, + Err(e) => get_error(format!("{}", e)), + } +} diff --git a/src/endpoints/quests/sithswap/claimable.rs b/src/endpoints/quests/sithswap/claimable.rs index 85087d3c..48002552 100644 --- a/src/endpoints/quests/sithswap/claimable.rs +++ b/src/endpoints/quests/sithswap/claimable.rs @@ -16,8 +16,8 @@ use starknet::{ use std::sync::Arc; const QUEST_ID: u32 = 5; -const TASK_IDS: &[u32] = &[20]; -const LAST_TASK: u32 = TASK_IDS[0]; +const TASK_IDS: &[u32] = &[20, 21, 55]; +const LAST_TASK: u32 = TASK_IDS[2]; const NFT_LEVEL: u32 = 7; #[derive(Deserialize)] diff --git a/src/endpoints/quests/sithswap/mod.rs b/src/endpoints/quests/sithswap/mod.rs index 4e642f70..6a407d43 100644 --- a/src/endpoints/quests/sithswap/mod.rs +++ b/src/endpoints/quests/sithswap/mod.rs @@ -1,2 +1,4 @@ pub mod claimable; pub mod verify_added_liquidity; +pub mod verify_quiz; +pub mod verify_twitter_fw; diff --git a/src/endpoints/quests/sithswap/verify_quiz.rs b/src/endpoints/quests/sithswap/verify_quiz.rs new file mode 100644 index 00000000..34a92388 --- /dev/null +++ b/src/endpoints/quests/sithswap/verify_quiz.rs @@ -0,0 +1,42 @@ +use std::sync::Arc; + +use crate::{ + common::verify_quiz::verify_quiz, + models::{AppState, VerifyQuizQuery}, + utils::{get_error, CompletedTasksTrait}, +}; +use axum::{extract::State, http::StatusCode, response::IntoResponse, Json}; +use serde_json::json; +use starknet::core::types::FieldElement; + +pub async fn handler( + State(state): State>, + body: Json, +) -> impl IntoResponse { + let task_id = 55; + if body.addr == FieldElement::ZERO { + return get_error("Please connect your wallet first".to_string()); + } + + let user_answers_numbers: Result>, _> = body + .user_answers_list + .iter() + .map(|inner_list| { + inner_list + .iter() + .map(|s| s.parse::()) + .collect::, _>>() + }) + .collect(); + + match user_answers_numbers { + Ok(responses) => match verify_quiz(&state.conf, body.addr, &body.quiz_name, &responses) { + true => match state.upsert_completed_task(body.addr, task_id).await { + Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), + Err(e) => get_error(format!("{}", e)), + }, + false => get_error("Incorrect answers".to_string()), + }, + Err(e) => get_error(format!("{}", e)), + } +} diff --git a/src/endpoints/quests/sithswap/verify_twitter_fw.rs b/src/endpoints/quests/sithswap/verify_twitter_fw.rs new file mode 100644 index 00000000..eb0cbc0c --- /dev/null +++ b/src/endpoints/quests/sithswap/verify_twitter_fw.rs @@ -0,0 +1,28 @@ +use std::sync::Arc; + +use crate::{ + models::{AppState, VerifyQuery}, + utils::{get_error, CompletedTasksTrait}, +}; +use axum::{ + extract::{Query, State}, + http::StatusCode, + response::IntoResponse, + Json, +}; +use serde_json::json; +use starknet::core::types::FieldElement; + +pub async fn handler( + State(state): State>, + Query(query): Query, +) -> impl IntoResponse { + let task_id = 21; + if query.addr == FieldElement::ZERO { + return get_error("Please connect your wallet first".to_string()); + } + match state.upsert_completed_task(query.addr, task_id).await { + Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), + Err(e) => get_error(format!("{}", e)), + } +} diff --git a/src/endpoints/quests/starknetid/claimable.rs b/src/endpoints/quests/starknetid/claimable.rs index 48e84c7f..e690f6a5 100644 --- a/src/endpoints/quests/starknetid/claimable.rs +++ b/src/endpoints/quests/starknetid/claimable.rs @@ -16,8 +16,8 @@ use starknet::{ use std::sync::Arc; const QUEST_ID: u32 = 1; -const TASK_IDS: &[u32] = &[5, 6, 7]; -const LAST_TASK: u32 = TASK_IDS[2]; +const TASK_IDS: &[u32] = &[5, 6, 7, 56]; +const LAST_TASK: u32 = TASK_IDS[3]; const NFT_LEVEL: u32 = 4; #[derive(Deserialize)] diff --git a/src/endpoints/quests/starknetid/mod.rs b/src/endpoints/quests/starknetid/mod.rs index 1c274166..5aa4c65a 100644 --- a/src/endpoints/quests/starknetid/mod.rs +++ b/src/endpoints/quests/starknetid/mod.rs @@ -1,5 +1,6 @@ -pub mod verify_twitter_fw; +pub mod claimable; pub mod verify_has_domain; pub mod verify_has_root_domain; +pub mod verify_quiz; pub mod verify_socials; -pub mod claimable; \ No newline at end of file +pub mod verify_twitter_fw; diff --git a/src/endpoints/quests/starknetid/verify_quiz.rs b/src/endpoints/quests/starknetid/verify_quiz.rs new file mode 100644 index 00000000..5e5986c5 --- /dev/null +++ b/src/endpoints/quests/starknetid/verify_quiz.rs @@ -0,0 +1,42 @@ +use std::sync::Arc; + +use crate::{ + common::verify_quiz::verify_quiz, + models::{AppState, VerifyQuizQuery}, + utils::{get_error, CompletedTasksTrait}, +}; +use axum::{extract::State, http::StatusCode, response::IntoResponse, Json}; +use serde_json::json; +use starknet::core::types::FieldElement; + +pub async fn handler( + State(state): State>, + body: Json, +) -> impl IntoResponse { + let task_id = 56; + if body.addr == FieldElement::ZERO { + return get_error("Please connect your wallet first".to_string()); + } + + let user_answers_numbers: Result>, _> = body + .user_answers_list + .iter() + .map(|inner_list| { + inner_list + .iter() + .map(|s| s.parse::()) + .collect::, _>>() + }) + .collect(); + + match user_answers_numbers { + Ok(responses) => match verify_quiz(&state.conf, body.addr, &body.quiz_name, &responses) { + true => match state.upsert_completed_task(body.addr, task_id).await { + Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), + Err(e) => get_error(format!("{}", e)), + }, + false => get_error("Incorrect answers".to_string()), + }, + Err(e) => get_error(format!("{}", e)), + } +} diff --git a/src/endpoints/quests/zklend/claimable.rs b/src/endpoints/quests/zklend/claimable.rs index 4c9ef537..004c5998 100644 --- a/src/endpoints/quests/zklend/claimable.rs +++ b/src/endpoints/quests/zklend/claimable.rs @@ -16,8 +16,8 @@ use starknet::{ use std::sync::Arc; const QUEST_ID: u32 = 6; -const TASK_IDS: &[u32] = &[24]; -const LAST_TASK: u32 = TASK_IDS[0]; +const TASK_IDS: &[u32] = &[24, 26, 53]; +const LAST_TASK: u32 = TASK_IDS[2]; const NFT_LEVEL: u32 = 8; #[derive(Deserialize)] diff --git a/src/endpoints/quests/zklend/mod.rs b/src/endpoints/quests/zklend/mod.rs index ffee90a8..f22f72db 100644 --- a/src/endpoints/quests/zklend/mod.rs +++ b/src/endpoints/quests/zklend/mod.rs @@ -1,2 +1,4 @@ pub mod claimable; pub mod verify_borrow; +pub mod verify_quiz; +pub mod verify_twitter_fw; diff --git a/src/endpoints/quests/zklend/verify_quiz.rs b/src/endpoints/quests/zklend/verify_quiz.rs new file mode 100644 index 00000000..ef539689 --- /dev/null +++ b/src/endpoints/quests/zklend/verify_quiz.rs @@ -0,0 +1,42 @@ +use std::sync::Arc; + +use crate::{ + common::verify_quiz::verify_quiz, + models::{AppState, VerifyQuizQuery}, + utils::{get_error, CompletedTasksTrait}, +}; +use axum::{extract::State, http::StatusCode, response::IntoResponse, Json}; +use serde_json::json; +use starknet::core::types::FieldElement; + +pub async fn handler( + State(state): State>, + body: Json, +) -> impl IntoResponse { + let task_id = 53; + if body.addr == FieldElement::ZERO { + return get_error("Please connect your wallet first".to_string()); + } + + let user_answers_numbers: Result>, _> = body + .user_answers_list + .iter() + .map(|inner_list| { + inner_list + .iter() + .map(|s| s.parse::()) + .collect::, _>>() + }) + .collect(); + + match user_answers_numbers { + Ok(responses) => match verify_quiz(&state.conf, body.addr, &body.quiz_name, &responses) { + true => match state.upsert_completed_task(body.addr, task_id).await { + Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), + Err(e) => get_error(format!("{}", e)), + }, + false => get_error("Incorrect answers".to_string()), + }, + Err(e) => get_error(format!("{}", e)), + } +} diff --git a/src/endpoints/quests/zklend/verify_twitter_fw.rs b/src/endpoints/quests/zklend/verify_twitter_fw.rs new file mode 100644 index 00000000..d1e7eb99 --- /dev/null +++ b/src/endpoints/quests/zklend/verify_twitter_fw.rs @@ -0,0 +1,28 @@ +use std::sync::Arc; + +use crate::{ + models::{AppState, VerifyQuery}, + utils::{get_error, CompletedTasksTrait}, +}; +use axum::{ + extract::{Query, State}, + http::StatusCode, + response::IntoResponse, + Json, +}; +use serde_json::json; +use starknet::core::types::FieldElement; + +pub async fn handler( + State(state): State>, + Query(query): Query, +) -> impl IntoResponse { + let task_id = 26; + if query.addr == FieldElement::ZERO { + return get_error("Please connect your wallet first".to_string()); + } + match state.upsert_completed_task(query.addr, task_id).await { + Ok(_) => (StatusCode::OK, Json(json!({"res": true}))).into_response(), + Err(e) => get_error(format!("{}", e)), + } +} diff --git a/src/main.rs b/src/main.rs index efced134..20ffa004 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,10 +66,6 @@ async fn main() { get(endpoints::get_trending_quests::handler), ) .route("/get_tasks", get(endpoints::get_tasks::handler)) - .route( - "/quests/starknetid/claimable", - get(endpoints::quests::starknetid::claimable::handler), - ) .route( "/quests/starknetid/verify_has_domain", get(endpoints::quests::starknetid::verify_has_domain::handler), @@ -86,6 +82,14 @@ async fn main() { "/quests/starknetid/verify_socials", get(endpoints::quests::starknetid::verify_socials::handler), ) + .route( + "/quests/starknetid/verify_quiz", + post(endpoints::quests::starknetid::verify_quiz::handler), + ) + .route( + "/quests/starknetid/claimable", + get(endpoints::quests::starknetid::claimable::handler), + ) .route( "/quests/jediswap/verify_added_liquidity", get(endpoints::quests::jediswap::verify_added_liquidity::handler), @@ -106,6 +110,14 @@ async fn main() { "/quests/zklend/verify_borrow", get(endpoints::quests::zklend::verify_borrow::handler), ) + .route( + "/quests/zklend/verify_twitter_fw", + get(endpoints::quests::zklend::verify_twitter_fw::handler), + ) + .route( + "/quests/zklend/verify_quiz", + post(endpoints::quests::zklend::verify_quiz::handler), + ) .route( "/quests/zklend/claimable", get(endpoints::quests::zklend::claimable::handler), @@ -118,6 +130,10 @@ async fn main() { "/quests/avnu/verify_swap", get(endpoints::quests::avnu::verify_swap::handler), ) + .route( + "/quests/avnu/verify_quiz", + post(endpoints::quests::avnu::verify_quiz::handler), + ) .route( "/quests/avnu/claimable", get(endpoints::quests::avnu::claimable::handler), @@ -142,6 +158,14 @@ async fn main() { "/quests/sithswap/verify_added_liquidity", get(endpoints::quests::sithswap::verify_added_liquidity::handler), ) + .route( + "/quests/sithswap/verify_twitter_fw", + get(endpoints::quests::sithswap::verify_twitter_fw::handler), + ) + .route( + "/quests/sithswap/verify_quiz", + post(endpoints::quests::sithswap::verify_quiz::handler), + ) .route( "/quests/sithswap/claimable", get(endpoints::quests::sithswap::claimable::handler),