Skip to content

Commit

Permalink
Feat/start marketplace program (AbdelStark#23)
Browse files Browse the repository at this point in the history
* refacto to generic function + change struct request + json value + params of the program in the content

* fix dese/ser issue + error gestion + start change in UI

* add program widefibo + page program internal with generic form + program card

* refacto wide_fibo program + struct with impl + wasm program

* poseidon + multi fibo program

* fix multi fibo program

* new program config + rename + refacto

* fix frontend build and clean

* refacto prover functions

* fix dvm test

* uncomment poseidon + wide_fib impl that break test because imported in the service_provider

* css nav + page + program + add poseidon & wide fibo stwo again

* start job launch program event kind + db

* utils + try fix poseidon program error

* fix program poseidon panic blocking

* fix breaking change stark proof stwo generic arg

* cargo fmt

* delete unused vars

* clippy + test

* clippy want to kill me i try to survive

* clean + clippy
  • Loading branch information
MSghais authored Aug 5, 2024
1 parent 816e1a7 commit 30ffeaf
Show file tree
Hide file tree
Showing 34 changed files with 2,557 additions and 116 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ license = "MIT"

[workspace.dependencies]
stwo-prover = { git = "https://github.com/starkware-libs/stwo.git" }
stwo_wasm = { path= "crates/stwo_wasm" }
tokio = { version = "1", default-features = false }
tracing = { version = "0.1", default-features = false }
tracing-subscriber = "0.3"
490 changes: 490 additions & 0 deletions askeladd-dvm-marketplace/src/app/components/ProgramCard.tsx

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions askeladd-dvm-marketplace/src/app/components/description/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useState } from "react";

export const HowItWork = () => {

const [openHowItWork, setOpenHowItWork] = useState(false);


return(
<div onClick={() => setOpenHowItWork(!openHowItWork)}
className="max-w-sm cursor-pointer my-5 p-1 m-1 whitespace-pre-line break-words"
>
<p className="text-white">How the ASKELADD DVM ZK works?</p>
{!openHowItWork &&
<button> Open </button>
}
{openHowItWork &&
<>
<div>
<p>As an User </p>
<p className="text-white">User send a JOB_REQUEST with different params on the Nostr event.</p>
<p className="text-white">It can change with all STWO Prover enabled on the Marketplace</p>
<p className="text-white mb-5">You need theses params on the Nostr event:</p>
<p>Inputs </p>

<p className="text-white">Request: {JSON.stringify({
"claim": "413300",
"log_size": "5"
})} &quot; The input of the Program</p>
<p className="text-white ">Tags: {`[
["param", "input_name", "value"] // The input of the Program
]`} </p>
</div>
<button> Close </button>
</>
}
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,25 @@ const Navbar: React.FC = () => {
data-collapse-toggle="navbar-sticky" type="button" className="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="navbar-sticky">
<span className="sr-only">Open main menu</span>
<svg className="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15" />
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M1 1h15M1 7h15M1 13h15" />
</svg>
</button>
</div>
{/* <div className={`items-center justify-between w-full md:flex md:w-auto md:order-1 ${isOpen ? 'flex' : 'hidden'}`} id="navbar-sticky"> */}

<div className={`items-center justify-between ${isOpen ? 'flex' : 'hidden'} w-full md:flex md:w-auto md:order-1`} id="navbar-sticky"> <ul className="flex flex-col p-4 md:p-0 mt-4 font-medium border border-gray-100 rounded-lg bg-gray-50 md:space-x-8 rtl:space-x-reverse md:flex-row md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
<li>
<Link href={"/config-marketplace"}
onClick={() => setIsOpen(!isOpen)}
className="text-white focus:outline-none font-medium rounded-lg text-sm px-4 py-2 text-center dark:focus:ring-blue-800">DVM ZK Config</Link>
</li>
</ul>
<div className={`gap-5 items-center justify-between ${isOpen ? 'flex' : 'hidden'} w-full md:flex md:w-auto md:order-1`} id="navbar-sticky">
<ul className="flex flex-col p-4 md:p-0 mt-4 font-medium rounded-lg md:space-x-8 rtl:space-x-reverse md:flex-row md:mt-0 md:border-0 dark:border-gray-700">
<li className='my-5'>
<Link href={"/stwo-program"}
onClick={() => setIsOpen(!isOpen)}
className="nav-button-link rounded m-5 text-white">STWO Program</Link>
</li>
<li className='my-5'>
<Link href={"/config-marketplace"}
onClick={() => setIsOpen(!isOpen)}
className="nav-button-link rounded m-5 text-white">DVM ZK Config</Link>
</li>
</ul>
</div>
</div>
</nav>
Expand Down
34 changes: 4 additions & 30 deletions askeladd-dvm-marketplace/src/app/config-marketplace/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Event as EventNostr, SimplePool } from "nostr-tools";
import { ASKELADD_KINDS, ConfigHandle } from "@/types";
import EventCard from "../components/EventCard";
import { generateContentAndTags } from "../utils/generateAppHandler";
import { HowItWork } from "../components/description";

export default function Home() {
const [publicKey, setPublicKey] = useState<string | undefined>();
Expand All @@ -23,7 +24,6 @@ export default function Home() {
>("idle");
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isInitialized, setIsInitialized] = useState(false);
const [openHowItWork, setOpenHowItWork] = useState(false);
const [isNeedLoadEvents, setIsNeedLoadEvents] = useState(true);
const [isAdmin, setIsAdmin] = useState(false);
const [timestampJob, setTimestampJob] = useState<number | undefined>();
Expand Down Expand Up @@ -114,7 +114,8 @@ export default function Home() {
let pubkey;
if (typeof window !== "undefined" && window.nostr) {
console.log("pubkey", pubkey)
if (!pubkey) return;
await connectExtension()
if (!publicKey) return;
const { tags, content } = generateContentAndTags(configKind, appKind, pubkey)
console.log("tags", tags)
console.log("content", content)
Expand Down Expand Up @@ -242,34 +243,7 @@ export default function Home() {
</div>
}

<div onClick={() => setOpenHowItWork(!openHowItWork)}
className="max-w-sm cursor-pointer my-5 p-1 m-1 whitespace-pre-line"
>
<p className="text-white">How the ASKELADD DVM ZK works?</p>
{!openHowItWork &&
<button> Open </button>
}
{openHowItWork &&
<>
<div>
<p>As an User </p>
<p className="text-white">User send a JOB_REQUEST with different params on the Nostr event.</p>
<p className="text-white">It can change with all STWO Prover enabled on the Marketplace</p>
<p className="text-white mb-5">You need theses params on the Nostr event:</p>
<p>Inputs </p>

<p className="text-white">Request: {JSON.stringify({
"claim": "413300",
"log_size": "5"
})} &quot; The input of the Program</p>
<p className="text-white ">Tags: {`[
["param", "input_name", "value"] // The input of the Program
]`} </p>
</div>
<button> Close </button>
</>
}
</div>
<HowItWork/>

<button
className={`block mb-5 font-bold py-2 px-4 rounded bg-blue-500 hover:bg-blue-700 ${isLoading ? "opacity-50 cursor-not-allowed" : ""}`}
Expand Down
16 changes: 16 additions & 0 deletions askeladd-dvm-marketplace/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,20 @@ main {
display: flex;
flex-direction: column;
align-items: center;
}

.nav-button,
.nav-button-link {
width: 100%;
background: var(--neon-green);
color: #000000;
border: 1px solid #000000;
box-shadow: 0 0 8px var(--neon-blue);
text-transform: uppercase;
letter-spacing: 1px;
font-weight: bold;
padding: 0.5rem 1rem;
border-radius: 0.25rem;
transition: all 0.3s ease;
text-shadow: none;
}
2 changes: 1 addition & 1 deletion askeladd-dvm-marketplace/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NostrProvider } from "@/context/NostrContext";
import "./globals.css";
import { Inter } from "next/font/google";
import Navbar from "./components/Navbar";
import Navbar from "./components/layout/Navbar";

const inter = Inter({ subsets: ["latin"] });

Expand Down
26 changes: 26 additions & 0 deletions askeladd-dvm-marketplace/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,20 +135,46 @@ export default function Home() {
['param', 'claim', claim.toString()],
['output', 'text/json']
];

const tags_values = [
['param', 'log_size', logSize.toString()],
['param', 'claim', claim.toString()],
];


const inputs:Map<string,string>= new Map<string,string>();

for(let tag of tags_values) {
inputs.set(tag[1], tag[2])
}
console.log("inputs",Object.fromEntries(inputs))

const content = JSON.stringify({
request: {
log_size: logSize.toString(),
claim: claim.toString()
},
program:{
contract_name:"FibonnacciProvingRequest",
internal_contract_name:"FibonnacciProvingRequest",
contract_reached:"InternalAskeladd",
// inputs:JSON.stringify(Object.fromEntries(inputs)),
inputs:Object.fromEntries(inputs),
// inputs:tags
}
})
// Define the timestamp before which you want to fetch events
// setTimestampJob(new Date().getTime() / 1000)
setTimestampJob(new Date().getTime())
console.log("inputs",inputs)
console.log("content",content)
// return ;
/** Use Nostr extension to send event */
const pool = new SimplePool();
const poolJob = new SimplePool();
const relay = await Relay.connect(ASKELADD_RELAY[0])
if (typeof window !== "undefined" && window.nostr) {

const pubkey = await window.nostr.getPublicKey();
let created_at = new Date().getTime();
setPublicKey(pubkey)
Expand Down
151 changes: 151 additions & 0 deletions askeladd-dvm-marketplace/src/app/stwo-program/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"use client";

import { useState, useEffect, useMemo } from "react";
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { useNostrContext } from "@/context/NostrContext";
import { useSendNote } from "@/hooks/useSendNote";
import { ContractUploadType, IGenerateZKPRequestDVM, JobResultProver, KIND_JOB_REQUEST, KIND_JOB_RESULT, ProgramInternalContractName } from "@/types";
import init, { verify_stark_proof, prove_and_verify } from "../../pkg/stwo_wasm";
import { useFetchEvents } from "@/hooks/useFetchEvents";
import { ASKELADD_RELAY } from "@/constants/relay";
import { Relay } from 'nostr-tools/relay';
import { Event as EventNostr, SimplePool } from "nostr-tools";
import { PROGRAM_INTERAL_REQUEST } from "@/constants/program";
import ProgramCard from "../components/ProgramCard";
export default function StwoProgramMarketplace() {
const [logSize, setLogSize] = useState<number>(5);
const [claim, setClaim] = useState<number>(443693538);
const [publicKey, setPublicKey] = useState<string | undefined>();
const [jobId, setJobId] = useState<string | undefined>();
const [error, setError] = useState<string | undefined>()
const [starkProof, setStarkProof] = useState<any | undefined>()
const [jobEventResult, setJobEventResult] = useState<EventNostr | undefined | NDKEvent>()
const [events, setEvents] = useState<EventNostr[] | NDKEvent[]>([])
const [selectedEvent, setSelectedEvent] = useState<EventNostr | undefined | NDKEvent>()
const [proofStatus, setProofStatus] = useState<
"idle" | "pending" | "received" | "verified"
>("idle");
const [proof, setProof] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isInitialized, setIsInitialized] = useState(false);
const [isFetchJob, setIsFetchJob] = useState(false);
const [isLoadingJobResult, setIsLoadingJobResult] = useState(false);
const [isWaitingJob, setIsWaitingJob] = useState(false);
const [timestampJob, setTimestampJob] = useState<number | undefined>();

const [internalProgram, setInternalProgram] = useState<IGenerateZKPRequestDVM[]>(PROGRAM_INTERAL_REQUEST)

let eventIdRequest = useMemo(() => {
return jobId
}, [jobId])
const { ndk, pool } = useNostrContext()
const { fetchEvents, fetchEventsTools, setupSubscriptionNostr } = useFetchEvents()
const { sendNote, publishNote } = useSendNote()

// Init wasm module to run_fibonacci_verify
useEffect(() => {
init()
.then(() => setIsInitialized(true))
.catch((error) => {
console.error("Failed to initialize WASM module:", error);

});
}, []);

/** Effect to fetch the job result when a job request is sent */
const waitingForJobResult = async () => {
if (jobEventResult && jobId) return;
fetchEventsProof()
setIsLoading(false);
setIsWaitingJob(false)
}
const timeoutWaitingForJobResult = async () => {
console.log("waiting timeout job result")
setTimeout(() => {
waitingForJobResult()
}, 5000);
}

useEffect(() => {
if (jobId && !jobEventResult) {
waitingForJobResult()
}
}, [jobId, isFetchJob, jobEventResult])



/** TODO fetch subscribed event
* fix search jobId => check if relayer support NIP-50
* Fetch Job result from the Prover
* - Tags: By reply of the event_id of the job request?
* - By author
* - Timestamp since/until (doesn't work as expected for me)
*/
const fetchEventsProof = async () => {
console.log("fetch events job result proof")
// if(jobEventResult && jobId)return;
setIsFetchJob(false);
setIsLoadingJobResult(true);
const { events } = await fetchEventsTools({
kind: KIND_JOB_RESULT,
// since: timestampJob,
// search: jobId
// search: `#${jobId}`,
})
console.log("events job result", events);
if (!events) return;
let lastEvent = events[events?.length - 1]
if (!lastEvent) return;
let id = jobId ?? eventIdRequest;
if (jobEventResult && jobEventResult?.id == id && proof && proofStatus != "pending") return;
if (id && !jobEventResult) {
let jobEventResultFind = events?.find((e) => e?.content?.includes(id))
console.log("jobEventResultFind", jobEventResultFind);
if (jobEventResultFind?.id) {
console.log("Event JOB_RESULT find", jobEventResultFind);
getDataOfEvent(jobEventResultFind);
setJobEventResult(jobEventResultFind)
}
}
}

const getDataOfEvent = (lastEvent?: NDKEvent | EventNostr) => {
if (!lastEvent || !lastEvent?.content) return;
setSelectedEvent(lastEvent);
setProof(lastEvent?.content?.toString())
const jobProofSerialize: any = JSON.parse(lastEvent?.content)
console.log('jobProofSerialize serialize', jobProofSerialize);
const proofSerialize = jobProofSerialize?.response?.proof;
console.log('proof serialize', proofSerialize);
setStarkProof(proofSerialize);
setProofStatus("received");
return proofSerialize
}

return (
<main className="min-h-screen bg-black text-neon-green font-arcade p-4 pb-16 relative overflow-hidden">
<div className="crt-overlay"></div>
<div className="scanlines"></div>
<div className="crt-curve"></div>

<div className="arcade-cabinet">
<h1 className="text-4xl mb-4 text-center glitch neon-text" data-text="Askeladd DVM Arcade">Askeladd DVM</h1>
<p className="text-1xl mb-2 text-center glitch neon-text" data-text="Askeladd DVM Arcade">STWO ZK Program Marketplace</p>
<p className="text-center blink neon-text-sm">Check the STWO Prover ready to use!</p>


<div className="gap-3"> {internalProgram?.map((p, i) => {
return (
<ProgramCard key={i} program={p}></ProgramCard>
)
})}

</div>

</div>
<div className="marquee">
<span>Prove your claims and conquer the Nostr realm!</span>
</div>
</main>
);
}
Loading

0 comments on commit 30ffeaf

Please sign in to comment.