# { "Depends": "py-genlayer:test" }
from genlayer import *
from dataclasses import dataclass
import typing
@allow_storage
@dataclass
class ProjectRecord:
owner: Address
name: str
category: str
description: str
repo_url: str
demo_url: str
docs_url: str
version_note: str
status: str
overall_score: u32
innovation_score: u32
genlayer_fit_score: u32
execution_score: u32
ux_score: u32
confidence: u32
one_liner: str
strengths: str
weaknesses: str
improvement_plan: str
evaluation_round: u32
class BuilderCourt(gl.Contract):
admin: Address
contest_name: str
theme: str
rubric: str
submissions_open: bool
project_count: u32
winner_project_id: str
winner_score: u32
project_ids: DynArray[str]
owner_to_project_id: TreeMap[Address, str]
projects: TreeMap[str, ProjectRecord]
def __init__(self, contest_name: str, theme: str, rubric: str):
self.admin = gl.message.sender_address
self.contest_name = contest_name
self.theme = theme
self.rubric = rubric
self.submissions_open = True
self.project_count = 0
self.winner_project_id = ""
self.winner_score = 0
def _require_admin(self):
if gl.message.sender_address != self.admin:
raise gl.UserError("admin only")
def _require_http_url(self, url: str):
if not (url.startswith("https://") or url.startswith("http://")):
raise gl.UserError("all URLs must start with http:// or https://")
def _zero_scores(self, project: ProjectRecord) -> ProjectRecord:
project.overall_score = 0
project.innovation_score = 0
project.genlayer_fit_score = 0
project.execution_score = 0
project.ux_score = 0
project.confidence = 0
project.one_liner = ""
project.strengths = ""
project.weaknesses = ""
project.improvement_plan = ""
return project
def _recompute_winner(self):
best_id = ""
best_overall = -1
best_fit = -1
best_execution = -1
for project_id in self.project_ids:
p = self.projects[project_id]
if p.status != "SCORED":
continue
overall = int(p.overall_score)
fit = int(p.genlayer_fit_score)
execution = int(p.execution_score)
better = False
if overall > best_overall:
better = True
elif overall == best_overall and fit > best_fit:
better = True
elif overall == best_overall and fit == best_fit and execution > best_execution:
better = True
if better:
best_id = project_id
best_overall = overall
best_fit = fit
best_execution = execution
self.winner_project_id = best_id
self.winner_score = 0 if best_overall < 0 else best_overall
@gl.public.write
def close_submissions(self):
self._require_admin()
self.submissions_open = False
@gl.public.write
def reopen_submissions(self):
self._require_admin()
self.submissions_open = True
@gl.public.write
def submit_project(
self,
name: str,
category: str,
description: str,
repo_url: str,
demo_url: str,
docs_url: str,
version_note: str,
) -> str:
if not self.submissions_open:
raise gl.UserError("submissions are closed")
if gl.message.sender_address in self.owner_to_project_id:
raise gl.UserError("this address already has a submission")
self._require_http_url(repo_url)
self._require_http_url(demo_url)
self._require_http_url(docs_url)
self.project_count += 1
project_id = f"project-{self.project_count}"
self.projects[project_id] = ProjectRecord(
owner=gl.message.sender_address,
name=name,
category=category,
description=description,
repo_url=repo_url,
demo_url=demo_url,
docs_url=docs_url,
version_note=version_note,
status="PENDING_REVIEW",
overall_score=0,
innovation_score=0,
genlayer_fit_score=0,
execution_score=0,
ux_score=0,
confidence=0,
one_liner="",
strengths="",
weaknesses="",
improvement_plan="",
evaluation_round=0,
)
self.project_ids.append(project_id)
self.owner_to_project_id[gl.message.sender_address] = project_id
return project_id
@gl.public.write
def update_my_project(
self,
description: str,
repo_url: str,
demo_url: str,
docs_url: str,
version_note: str,
):
sender = gl.message.sender_address
if sender not in self.owner_to_project_id:
raise gl.UserError("no submission found for sender")
self._require_http_url(repo_url)
self._require_http_url(demo_url)
self._require_http_url(docs_url)
project_id = self.owner_to_project_id[sender]
project = self.projects[project_id]
project.description = description
project.repo_url = repo_url
project.demo_url = demo_url
project.docs_url = docs_url
project.version_note = version_note
project.status = "PENDING_REVIEW"
project = self._zero_scores(project)
self.projects[project_id] = project
self._recompute_winner()
@gl.public.write
def evaluate_project(self, project_id: str):
if project_id not in self.projects:
raise gl.UserError("unknown project id")
project = gl.storage.copy_to_memory(self.projects[project_id])
contest_name = self.contest_name
theme = self.theme
rubric = self.rubric
def clip(text: str, limit: int) -> str:
if len(text) <= limit:
return text
return text[:limit]
def to_int(raw: typing.Any, field: str) -> int:
if isinstance(raw, bool):
raise gl.UserError(f"invalid boolean for {field}")
if isinstance(raw, int):
return raw
if isinstance(raw, float):
return int(round(raw))
if isinstance(raw, str):
return int(float(raw.strip()))
raise gl.UserError(f"invalid type for {field}")
def normalize(raw: typing.Any) -> dict[str, typing.Any]:
if not isinstance(raw, dict):
raise gl.UserError("judge output must be a JSON object")
data = {
"overall_score": max(0, min(100, to_int(raw.get("overall_score"), "overall_score"))),
"innovation_score": max(0, min(100, to_int(raw.get("innovation_score"), "innovation_score"))),
"genlayer_fit_score": max(0, min(100, to_int(raw.get("genlayer_fit_score"), "genlayer_fit_score"))),
"execution_score": max(0, min(100, to_int(raw.get("execution_score"), "execution_score"))),
"ux_score": max(0, min(100, to_int(raw.get("ux_score"), "ux_score"))),
"confidence": max(0, min(100, to_int(raw.get("confidence"), "confidence"))),
"recommended_status": str(raw.get("recommended_status", "")).strip().lower(),
"one_liner": clip(str(raw.get("one_liner", "")).strip(), 220),
"strengths": clip(str(raw.get("strengths", "")).strip(), 500),
"weaknesses": clip(str(raw.get("weaknesses", "")).strip(), 500),
"improvement_plan": clip(str(raw.get("improvement_plan", "")).strip(), 500),
}
if data["recommended_status"] not in ("accept", "needs_work", "incomplete"):
raise gl.UserError("recommended_status must be accept, needs_work, or incomplete")
if data["one_liner"] == "":
raise gl.UserError("one_liner is required")
return data
def fetch_excerpt(url: str) -> str:
body = gl.nondet.web.get(url).body.decode("utf-8")
return clip(body, 6000)
def leader_fn():
repo_text = fetch_excerpt(project.repo_url)
demo_text = fetch_excerpt(project.demo_url)
docs_text = fetch_excerpt(project.docs_url)
prompt = f"""
You are an expert judge for a GenLayer builder competition.
Contest name: {contest_name}
Theme: {theme}
Rubric: {rubric}
Submission:
- Project name: {project.name}
- Category: {project.category}
- Description: {project.description}
- Version note: {project.version_note}
- Repo URL: {project.repo_url}
- Demo URL: {project.demo_url}
- Docs URL: {project.docs_url}
Evidence excerpts:
[REPO]
{repo_text}
[DEMO]
{demo_text}
[DOCS]
{docs_text}
Score the project for a GenLayer-native competition.
Scoring guidance:
- innovation_score: originality and ambition
- genlayer_fit_score: how strongly the project uses GenLayer-native capabilities like subjective judgment, live web access, LLM-backed reasoning, or trustless decision-making
- execution_score: how complete and credible the implementation looks from evidence
- ux_score: clarity of product and ease of understanding
- overall_score: weighted holistic result, not a raw average
- confidence: how confident you are based on the evidence shown
recommended_status rules:
- "accept" for standout, credible, GenLayer-native projects
- "needs_work" for real but not yet strong enough projects
- "incomplete" when evidence is thin, broken, or mostly conceptual
Return JSON only with exactly these keys:
overall_score
innovation_score
genlayer_fit_score
execution_score
ux_score
confidence
recommended_status
one_liner
strengths
weaknesses
improvement_plan
"""
raw = gl.nondet.exec_prompt(prompt, response_format="json")
return normalize(raw)
def validator_fn(leader_result) -> bool:
if not isinstance(leader_result, gl.vm.Return):
return False
try:
proposed = normalize(leader_result.calldata)
local = leader_fn()
if proposed["recommended_status"] != local["recommended_status"]:
return False
if abs(proposed["overall_score"] - local["overall_score"]) > 15:
return False
if abs(proposed["innovation_score"] - local["innovation_score"]) > 20:
return False
if abs(proposed["genlayer_fit_score"] - local["genlayer_fit_score"]) > 15:
return False
if abs(proposed["execution_score"] - local["execution_score"]) > 20:
return False
if abs(proposed["ux_score"] - local["ux_score"]) > 20:
return False
if proposed["overall_score"] < 40 and local["overall_score"] >= 70:
return False
if proposed["overall_score"] >= 70 and local["overall_score"] < 40:
return False
return True
except Exception:
return False
result = gl.vm.run_nondet_unsafe(leader_fn, validator_fn)
stored = self.projects[project_id]
stored.overall_score = result["overall_score"]
stored.innovation_score = result["innovation_score"]
stored.genlayer_fit_score = result["genlayer_fit_score"]
stored.execution_score = result["execution_score"]
stored.ux_score = result["ux_score"]
stored.confidence = result["confidence"]
stored.one_liner = result["one_liner"]
stored.strengths = result["strengths"]
stored.weaknesses = result["weaknesses"]
stored.improvement_plan = result["improvement_plan"]
stored.status = "SCORED"
stored.evaluation_round += 1
self.projects[project_id] = stored
self._recompute_winner()
@gl.public.view
def get_project(self, project_id: str) -> typing.Any:
if project_id not in self.projects:
raise gl.UserError("unknown project id")
return self.projects[project_id]
@gl.public.view
def get_my_project_id(self) -> str:
return self.owner_to_project_id.get(gl.message.sender_address, "")
@gl.public.view
def get_winner(self) -> typing.Any:
if self.winner_project_id == "":
return {
"winner_project_id": "",
"winner_score": 0,
}
winner = self.projects[self.winner_project_id]
return {
"winner_project_id": self.winner_project_id,
"winner_score": self.winner_score,
"name": winner.name,
"owner": str(winner.owner),
"one_liner": winner.one_liner,
}
@gl.public.view
def get_leaderboard(self) -> typing.Any:
rows = []
for project_id in self.project_ids:
p = self.projects[project_id]
rows.append({
"project_id": project_id,
"name": p.name,
"owner": str(p.owner),
"category": p.category,
"status": p.status,
"overall_score": p.overall_score,
"innovation_score": p.innovation_score,
"genlayer_fit_score": p.genlayer_fit_score,
"execution_score": p.execution_score,
"ux_score": p.ux_score,
"confidence": p.confidence,
"one_liner": p.one_liner,
})
rows.sort(
key=lambda row: (
-int(row["overall_score"]),
-int(row["genlayer_fit_score"]),
-int(row["execution_score"]),
row["name"],
)
)
return rows
GenLayer Builder CourtTrustless decision-making with live web evidenceReward projects that deeply use GenLayer-native capabilities, not generic wrappers