diff --git a/src/actions/submit-challenge.ts b/src/actions/submit-challenge.ts index bb07b2c..b9e96e1 100644 --- a/src/actions/submit-challenge.ts +++ b/src/actions/submit-challenge.ts @@ -1,8 +1,45 @@ -import { loadUserState } from "../utils/state-manager"; -import { submitChallengeToServer } from "../modules/api"; +import { confirm, input } from "@inquirer/prompts"; import chalk from "chalk"; -import { input } from "@inquirer/prompts"; +import { getAuthMessage, submitChallengeToServer } from "../modules/api"; import { isValidAddress } from "../utils/helpers"; +import { requestSignature } from "../utils/request-signature"; +import { loadUserState } from "../utils/state-manager"; + +async function requestSignatureWithRetry(authMessage: string): Promise { + console.log("Requesting signature..."); + + let signature: string | undefined; + let err: string | undefined; + + do { + if (err) { + + console.log(chalk.red(`User rejected request. Signature is required to submit.`)); + const tryAgain = await confirm({ + message: "Would you like to try signing again?", + default: true + }); + + if (!tryAgain) { + console.log("Signature request cancelled."); + throw new Error("Signature request cancelled by user"); + } + + process.stdout.write("\x1b[2A\x1b[0J"); + } + + const { data, error } = await requestSignature(authMessage); + signature = data; + err = error; + } while (err); + + if (!signature) { + throw new Error("Failed to get signature after all attempts."); + } + + console.log("✅ Signature received!"); + return signature; +} export async function submitChallenge(name: string, contractAddress?: string) { const { address: userAddress } = loadUserState(); @@ -15,12 +52,15 @@ export async function submitChallenge(name: string, contractAddress?: string) { const answer = await input(question); contractAddress = answer; } - + + const authMessage = await getAuthMessage(userAddress as string); + const signature = await requestSignatureWithRetry(authMessage); + console.log("Submitting challenge..."); console.log(""); // Send the contract address to the server - const response = await submitChallengeToServer(userAddress as string, name, contractAddress as string); + const response = await submitChallengeToServer(userAddress as string, name, contractAddress as string, signature); if (response.result) { const { passed, failingTests, error } = response.result; if (passed) { diff --git a/src/modules/api.ts b/src/modules/api.ts index 6bc7e5d..736e02e 100644 --- a/src/modules/api.ts +++ b/src/modules/api.ts @@ -56,14 +56,14 @@ export const upsertUser = async (userData: { address?: string, ens?: string, dev /** * Submit Challenge */ -export const submitChallengeToServer = async (userAddress: string, challengeName: string, contractAddress: string) => { +export const submitChallengeToServer = async (userAddress: string, challengeName: string, contractAddress: string, signature: string) => { try { const response = await fetch(`${API_URL}/submit`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ challengeName, contractAddress, userAddress }), + body: JSON.stringify({ challengeName, contractAddress, userAddress, signature }), }); const data = await response.json(); return data; @@ -105,3 +105,30 @@ export const fetchLeaderboard = async () => { return []; } }; + +/** + * Get Authentication Message + */ +export const getAuthMessage = async (userAddress: string) => { + try { + const response = await fetch(`${API_URL}/message/${userAddress}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + if (response.status === 404) { + throw new Error('User not found'); + } + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + return data.message; + } catch (error) { + console.error('Error fetching auth message:', error); + throw error; + } +}; diff --git a/src/utils/request-signature.ts b/src/utils/request-signature.ts new file mode 100644 index 0000000..99d936c --- /dev/null +++ b/src/utils/request-signature.ts @@ -0,0 +1,9 @@ +import { SafeSigner } from "safe-signer"; + +export const requestSignature = async (message: string) => { + const signer = new SafeSigner(); + await signer.start(); + const response = await signer.sendRequest({message} as any); + signer.stop(); + return response; +}