Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b514519
Add 1st draft of the new types
Y3drk Apr 29, 2026
d7278fd
Refactor data to match the drafted data model + add mock images and a…
Y3drk Apr 29, 2026
8e692b6
Basic UI adaptation to the new data model, pt. 1
Y3drk Apr 29, 2026
f35b9b5
Basic UI adaptation to the new data model, pt.2
Y3drk May 5, 2026
2fce38b
Apply ai assistant's suggestions, pt.1
Y3drk May 6, 2026
d7e3f4c
Refine apps' benchmarks data organization
Y3drk May 7, 2026
5ef4e6f
JSDocs improvements, pt.1
Y3drk May 7, 2026
cb4969c
Refine best practices data organization
Y3drk May 7, 2026
9ae8c2d
Adjust UI according to established goals
Y3drk May 7, 2026
eaec4c3
Update CONTRIBUTING.md and polish some JSDocs
Y3drk May 7, 2026
1b96f1a
Apply ai assistant's suggestions, pt.2
Y3drk May 7, 2026
9e9aa00
Apply 05/08/26 review feedback (GitHub + Google Doc), pt.1 - majority…
Y3drk May 11, 2026
bb1b2c6
Remove all placeholder content and align acceptance test benchmark re…
Y3drk May 11, 2026
0c060b6
Apply 05/11/26 Slack feedback
Y3drk May 11, 2026
8dd6549
Apply ai assistant's suggestions, pt.3
Y3drk May 11, 2026
5542d92
Resolve conflicts with main
Y3drk May 11, 2026
e6773bf
UI double-check + initial work on technical details content refinement
Y3drk May 11, 2026
e79ae89
Apply ai assistant's suggestions, pt.4
Y3drk May 12, 2026
7efbbef
Fix audited dependency vulnerabilities
Y3drk May 12, 2026
2d93d38
Apply 05/11/26 Google doc feedback
Y3drk May 12, 2026
161dd35
Apply 05/12/26 GitHub review feedback
Y3drk May 12, 2026
9faf4b4
Apply ai assistant's suggestions, pt.5
Y3drk May 12, 2026
8d3a637
Apply 05/12/26 Google Doc UI feedback
Y3drk May 12, 2026
afd0fbd
Apply ai assistant's suggestions, pt.6
Y3drk May 12, 2026
d4a4482
Apply ai assistant's suggestions, pt.7 + minor fixes after self-review
Y3drk May 12, 2026
25d43d7
Apply 05/13/26 GitHub review feedback
Y3drk May 13, 2026
35c7e4a
Apply ai assistant's suggestions, pt.8
Y3drk May 13, 2026
c935f7f
Upload final versions of adjusted contract naming season OG images
Y3drk May 13, 2026
1870bc0
Apply ai assistant's suggestions, pt.9
Y3drk May 13, 2026
61ad7f6
Add Safe & Rabby
Y3drk May 16, 2026
e678c27
Add Ready & Zerion
Y3drk May 18, 2026
5a9f69a
Add Status & add contributing comments in data/projects/*/index.ts an…
Y3drk May 18, 2026
d384e95
Add Ledger & World
Y3drk May 21, 2026
91a880d
Add DeFi app type
Y3drk May 21, 2026
b92a0b3
Add DeFi apps for Aave, Uniswap & 1inch
Y3drk May 22, 2026
8dbab09
Correct slugs for Ledger & Ready
Y3drk May 22, 2026
6cf9f90
Add Trust
Y3drk May 22, 2026
a1daa0f
Merge branch 'y3drk/chore/add-new-apps-t1-may26' of https://github.co…
Y3drk May 22, 2026
681dc06
Add Phantom
Y3drk May 22, 2026
a9fcc60
Add Curve & Lido
Y3drk May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 192 additions & 45 deletions CONTRIBUTING.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions ensawards.org/data/acceptance-tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ACCEPTANCE_TESTS } from "data/acceptance-tests";
import { isValidSlug } from "data/shared/slugs";
import { describe, expect, it } from "vitest";

import { areStringsUnique } from "@/utils";

describe("Acceptance test data", () => {
it("Should have valid and unique slugs", () => {
const slugArray: string[] = [];

ACCEPTANCE_TESTS.forEach((acceptanceTest) => {
expect(
isValidSlug(acceptanceTest.acceptanceTestSlug),
`Slug={${acceptanceTest.acceptanceTestSlug}} is not valid`,
).toEqual(true);

slugArray.push(acceptanceTest.acceptanceTestSlug);
});

expect(areStringsUnique(slugArray), `Slugs for Acceptance Tests are not unique`).toEqual(true);
});
});
5 changes: 5 additions & 0 deletions ensawards.org/data/acceptance-tests/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ENS_BEST_PRACTICES } from "data/ens-best-practices";

export const ACCEPTANCE_TESTS = [
...ENS_BEST_PRACTICES.flatMap((bestPractice) => bestPractice.technicalDetails.acceptanceTests),
];
98 changes: 98 additions & 0 deletions ensawards.org/data/acceptance-tests/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { type BenchmarkResult, BenchmarkResults } from "data/benchmarks/types";
import type { Contribution } from "data/contributors/types";
import type { JSX } from "react";

/** A unique identifier for an acceptance test.
*
* @invariant Must be unique across all acceptance tests.
* @invariant Must match {@link ENSAWARDS_SLUG_PATTERN}.
*/
export type AcceptanceTestSlug = string;

/**
* Represents an acceptance test that an app can be evaluated against.
*/
export interface AcceptanceTest {
/**
* Unique identifier for the acceptance test.
*/
acceptanceTestSlug: AcceptanceTestSlug;

/**
* Description of the acceptance test,
* which should provide clear and detailed information
* about the criteria and requirements that
* an {@link App} must meet to pass the test.
* This may include specific functionalities to be tested,
* user interactions to be evaluated,
* and any relevant technical details or considerations.
*
* @note The description should not include examples of passed or failed benchmarks,
* there are dedicated fields for that
* (see {@link AcceptanceTest.examplePass},
* {@link AcceptanceTest.examplePartialPass},
* or {@link AcceptanceTest.exampleFail}).
*/
description: JSX.Element;

/**
* Examples of benchmark results that illustrate
* what a passing, partially passing, or failing result
* looks like for this acceptance test.
*/
examplePass: AcceptanceTestBenchmarkPass;
examplePartialPass?: AcceptanceTestBenchmarkPartialPass;
exampleFail?: AcceptanceTestBenchmarkFail;
}

/**
* Represents the benchmark of an {@link AcceptanceTest} on an {@link App} against a {@link BestPractice}.
*/
export interface AcceptanceTestBenchmarkAbstract<BenchmarkResultT extends BenchmarkResult> {
/** The result of the benchmark */
result: BenchmarkResultT;

/** A record of all contributors involved
* in the addition or maintenance of the benchmark's data.
*
* @invariant Multiple {@link Contribution} from the same contributor
* on the same app benchmark are not allowed.
* When a contributor makes updates to their existing contribution,
* they should update the `lastUpdated` timestamp of their existing `Contribution`.
*/
contributions: [Contribution, ...Contribution[]];

/**
* Notes about how the benchmark result was determined,
* which may include details about the testing process,
* any challenges encountered, and explanations,
* as well as a visual proof, for the final result.
*/
notes: JSX.Element;
}

/**
* Represents a benchmark of an {@link AcceptanceTest} on an {@link App} against a {@link BestPractice},
* that has fully passed the acceptance test.
*/
export interface AcceptanceTestBenchmarkPass
extends AcceptanceTestBenchmarkAbstract<typeof BenchmarkResults.Pass> {}

/**
* Represents a benchmark of an {@link AcceptanceTest} on an {@link App} against a {@link BestPractice},
* that has partially passed the acceptance test.
*/
export interface AcceptanceTestBenchmarkPartialPass
extends AcceptanceTestBenchmarkAbstract<typeof BenchmarkResults.PartialPass> {}

/**
* Represents a benchmark of an {@link AcceptanceTest} on an {@link App} against a {@link BestPractice},
* that hasn't passed the acceptance test.
*/
export interface AcceptanceTestBenchmarkFail
extends AcceptanceTestBenchmarkAbstract<typeof BenchmarkResults.Fail> {}

export type AcceptanceTestBenchmark =
| AcceptanceTestBenchmarkPass
| AcceptanceTestBenchmarkPartialPass
| AcceptanceTestBenchmarkFail;
95 changes: 95 additions & 0 deletions ensawards.org/data/acceptance-tests/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { generalizeAcceptanceTestBenchmarks } from "data/acceptance-tests/utils";
import { type AcceptanceTestBenchmarks, BenchmarkResults } from "data/benchmarks/types";
import { createMockAcceptanceTestBenchmark } from "data/shared/test-utils";
import { describe, expect, it } from "vitest";

describe("Acceptance test utils", () => {
describe("generalizeAcceptanceTestBenchmarks", () => {
it(
"Returns `BenchmarkResults.Pass` if in all defined benchmarks there is at least one `BenchmarkResults.Pass`" +
" and all others are `BenchmarkResults.Pass` or `BenchmarkResults.PartialPass`",
() => {
const expectedResult = BenchmarkResults.Pass;

const inputBenchmarks = {
"mock-acceptance-test-1": createMockAcceptanceTestBenchmark(BenchmarkResults.Pass),
"mock-acceptance-test-2": createMockAcceptanceTestBenchmark(BenchmarkResults.PartialPass),
"mock-acceptance-test-3": undefined,
// pending benchmarks should be ignored in this case of the generalization
} as const satisfies AcceptanceTestBenchmarks;

expect(
generalizeAcceptanceTestBenchmarks(inputBenchmarks),
"generalizeAcceptanceTestBenchmarks should return `BenchmarkResults.Pass`",
).toEqual(expectedResult);
},
);

it("Returns `BenchmarkResults.Fail` if all defined benchmarks are `BenchmarkResults.Fail`", () => {
const expectedResult = BenchmarkResults.Fail;

const inputBenchmarks = {
"mock-acceptance-test-1": createMockAcceptanceTestBenchmark(BenchmarkResults.Fail),
"mock-acceptance-test-2": createMockAcceptanceTestBenchmark(BenchmarkResults.Fail),
"mock-acceptance-test-3": undefined,
// pending benchmarks should be ignored in this case of the generalization
} as const satisfies AcceptanceTestBenchmarks;

expect(
generalizeAcceptanceTestBenchmarks(inputBenchmarks),
"generalizeAcceptanceTestBenchmarks should return `BenchmarkResults.Fail`",
).toEqual(expectedResult);
});

it(
"Returns `BenchmarkResults.PartialPass` if at least one defined benchmark is `BenchmarkResults.Fail`" +
" and at least one defined benchmark is `BenchmarkResults.Pass`",
() => {
const expectedResult = BenchmarkResults.PartialPass;

const inputBenchmarks = {
"mock-acceptance-test-1": createMockAcceptanceTestBenchmark(BenchmarkResults.Fail),
"mock-acceptance-test-2": createMockAcceptanceTestBenchmark(BenchmarkResults.Pass),
"mock-acceptance-test-3": createMockAcceptanceTestBenchmark(BenchmarkResults.PartialPass),
"mock-acceptance-test-4": undefined,
// pending benchmarks should be ignored in this case of the generalization
} as const satisfies AcceptanceTestBenchmarks;

expect(
generalizeAcceptanceTestBenchmarks(inputBenchmarks),
"generalizeAcceptanceTestBenchmarks should return `BenchmarkResults.PartialPass`",
).toEqual(expectedResult);
},
);

it("Returns `BenchmarkResults.PartialPass` if all defined benchmarks are `BenchmarkResults.PartialPass`", () => {
const expectedResult = BenchmarkResults.PartialPass;

const inputBenchmarks = {
"mock-acceptance-test-1": createMockAcceptanceTestBenchmark(BenchmarkResults.PartialPass),
"mock-acceptance-test-2": createMockAcceptanceTestBenchmark(BenchmarkResults.PartialPass),
"mock-acceptance-test-3": undefined,
// pending benchmarks should be ignored in this case of the generalization
} as const satisfies AcceptanceTestBenchmarks;

expect(
generalizeAcceptanceTestBenchmarks(inputBenchmarks),
"generalizeAcceptanceTestBenchmarks should return `BenchmarkResults.PartialPass`",
).toEqual(expectedResult);
});

it("Returns `undefined` if all benchmarks are `undefined` (pending)", () => {
const expectedResult = undefined;

const inputBenchmarks = {
"mock-acceptance-test-1": undefined,
"mock-acceptance-test-2": undefined,
} as const satisfies AcceptanceTestBenchmarks;

expect(
generalizeAcceptanceTestBenchmarks(inputBenchmarks),
"generalizeAcceptanceTestBenchmarks should return `undefined` for all pending benchmarks",
).toEqual(expectedResult);
});
});
});
90 changes: 90 additions & 0 deletions ensawards.org/data/acceptance-tests/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { ACCEPTANCE_TESTS } from "data/acceptance-tests";
import type {
AcceptanceTest,
AcceptanceTestBenchmark,
AcceptanceTestSlug,
} from "data/acceptance-tests/types";
import type { AppSlug } from "data/apps/types";
import {
type AcceptanceTestBenchmarks,
type BenchmarkResult,
BenchmarkResults,
} from "data/benchmarks/types";
import { getAppBenchmarks } from "data/benchmarks/utils.ts";

/** Returns an {@link AcceptanceTest} by {@link AcceptanceTestSlug}. */
export const getAcceptanceTestBySlug = (slug: AcceptanceTestSlug): AcceptanceTest | undefined => {
return ACCEPTANCE_TESTS.find((acceptanceTest) => acceptanceTest.acceptanceTestSlug === slug);
};

/** Returns all {@link AcceptanceTestBenchmark}s of an `App` by {@link AppSlug}. */
export const getAcceptanceTestBenchmarksByApp = (
appSlug: AppSlug,
): (AcceptanceTestBenchmark | undefined)[] => {
const appBenchmarks = getAppBenchmarks(appSlug);

return Object.values(appBenchmarks).flatMap((acceptanceTestBenchmarks) =>
Object.values(acceptanceTestBenchmarks),
);
};

/**
* Generalizes multiple `AcceptanceTestBenchmark`s into a single `BenchmarkResult`
* based on the following rules:
* - Returns {@link BenchmarkResults.Pass} if:
* - in all defined benchmarks there is at least one
* {@link BenchmarkResults.Pass}
* - and all others are {@link BenchmarkResults.Pass} or {@link BenchmarkResults.PartialPass}
*
* - Returns {@link BenchmarkResults.Fail} if all defined benchmarks
* are {@link BenchmarkResults.Fail},
*
* - Returns {@link BenchmarkResults.PartialPass} if:
* - at least one defined benchmark is {@link BenchmarkResults.Fail}
* and at least one defined benchmark is
* {@link BenchmarkResults.Pass} or {@link BenchmarkResults.PartialPass},
* - or all defined benchmarks are {@link BenchmarkResults.PartialPass},
*
* - Returns `undefined` if all benchmarks are `undefined` (pending).
*/
export const generalizeAcceptanceTestBenchmarks = (
acceptanceTestBenchmarks: AcceptanceTestBenchmarks,
): BenchmarkResult | undefined => {
const benchmarkResults = Object.values(acceptanceTestBenchmarks).map(
(benchmark) => benchmark?.result,
);

const definedBenchmarkResults = benchmarkResults.filter((result) => result !== undefined);

if (definedBenchmarkResults.length === 0) {
return undefined;
}

const allDefinedBenchmarksPassPartially = definedBenchmarkResults.every(
(result) => result === BenchmarkResults.PartialPass,
);

if (allDefinedBenchmarksPassPartially) {
return BenchmarkResults.PartialPass;
}

// For now, we'll explicitly treat pass and partial pass equally
// (For cases where not all benchmarks are partial pass)
const allDefinedBenchmarksPass = definedBenchmarkResults.every(
(result) => result === BenchmarkResults.Pass || result === BenchmarkResults.PartialPass,
);

if (allDefinedBenchmarksPass) {
return BenchmarkResults.Pass;
}

const allDefinedBenchmarksFail = definedBenchmarkResults.every(
(result) => result === BenchmarkResults.Fail,
);

if (allDefinedBenchmarksFail) {
return BenchmarkResults.Fail;
}

return BenchmarkResults.PartialPass;
};
20 changes: 20 additions & 0 deletions ensawards.org/data/apps/1inch-defi-app/benchmarks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Read https://github.com/namehash/ensawards/blob/main/CONTRIBUTING.md
// for additional advice on adding and modifying app benchmarks

import OneInchDeFiApp from "data/apps/1inch-defi-app";
import { defineAppBenchmarks } from "data/benchmarks/registry";
import type { BestPracticeBenchmarks } from "data/ens-best-practices/types";

// TODO; Add proper benchmarks
const benchmarks: BestPracticeBenchmarks = {
"display-named-smart-contracts-mainnet": {
"mainnet-interactions-display-named-smart-contracts": undefined,
},
"display-named-smart-contracts-l2-chains": {
"l2-chain-interactions-display-named-smart-contracts": undefined,
},
};

defineAppBenchmarks(OneInchDeFiApp, benchmarks);

export default benchmarks;
23 changes: 23 additions & 0 deletions ensawards.org/data/apps/1inch-defi-app/icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";

const Icon = ({ className, ...props }: React.SVGProps<SVGSVGElement>) => (
<svg
id="1"
data-name="1"
Comment on lines +5 to +6
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove static SVG IDs to avoid duplicate DOM IDs across multiple renders.

Hardcoded id="1"/data-name="1" can duplicate on pages rendering this icon more than once.

Suggested fix
   <svg
-    id="1"
-    data-name="1"
     xmlns="http://www.w3.org/2000/svg"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
id="1"
data-name="1"
<svg
xmlns="http://www.w3.org/2000/svg"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ensawards.org/data/apps/1inch-defi-app/icon.tsx` around lines 5 - 6, The SVG
in icon.tsx contains hardcoded attributes id="1" and data-name="1" which will
create duplicate DOM IDs when the icon is rendered multiple times; update the
component to remove static IDs or generate unique IDs per instance (e.g., use
React.useId() or accept an id/idPrefix prop) and replace id="1" and any internal
references that rely on it with the generated value (you can also drop data-name
if it's unused) so each rendered icon has a unique identifier.

xmlns="http://www.w3.org/2000/svg"
width="181mm"
height="181mm"
version="1.1"
viewBox="0 0 513 513"
className={className}
{...props}
>
<path d="M512.8,0H0v512.8h512.8V0Z" />
<path
d="M169.7,383.7h172.9v-36.7h-63.8s0-218.7,0-218.7h-37.8c-1.5,30.6-10.3,38.3-52.1,38.3h-19.2v34.6h63.8v145.8h-63.8v36.7ZM360.7,201.2v-72.9h-36.7v72.9h36.7ZM425.1,201.2v-72.9h-36.7v72.9h36.7Z"
fill="#fff"
/>
</svg>
);

export default Icon;
30 changes: 30 additions & 0 deletions ensawards.org/data/apps/1inch-defi-app/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Read https://github.com/namehash/ensawards/blob/main/CONTRIBUTING.md
// for additional advice on adding and modifying apps

import OneInchProject from "data/projects/1inch/index.ts";
import { asInterpretedName } from "enssdk";

import { defineApp } from "../registry.ts";
import { type App, AppTypes } from "../types.ts";
import OneInchIcon from "./icon.tsx";

const OneInchDeFiApp: App = {
id: "1inch-defi-app",
appSlug: "1inch-defi-app",
type: AppTypes.DeFi,
project: OneInchProject,
name: '1inch"',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix malformed app name string.

Line 16 includes an extra trailing quote in the displayed name ('1inch"'), so the UI will show a typo.

Proposed fix
-  name: '1inch"',
+  name: "1inch",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
name: '1inch"',
name: "1inch",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ensawards.org/data/apps/1inch-defi-app/index.ts` at line 16, The app metadata
has a malformed name string: the property name in the exported app object
(symbol "name" in index.ts) is set to '1inch"' with an extra trailing quote; fix
it by editing the "name" value to the correct single-quoted string '1inch'
(remove the stray double-quote) so the UI displays the proper app name.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: '1inch"',
name: '1inch',

App name field contains stray double quote character at the end: '1inch"' instead of '1inch'

Fix on Vercel

Comment thread
vercel[bot] marked this conversation as resolved.
description:
"A DeFi aggregator app for swapping tokens across 13+ chains with the only native connection between Solana and EVM networks, with true self-custody and built-in security.",
socials: {
website: new URL("https://1inch.com/swap"),
twitter: new URL("https://x.com/1inch"),
ens: asInterpretedName("1inch.eth"),
},
icon: OneInchIcon, // TODO: The icon is not perfect for dark bgs. Same case as with Ledger. Brainstorm fix ideas (but no hacky ifs in the code)
// TODO: Add OG images
};

defineApp(OneInchDeFiApp);

export default OneInchDeFiApp;
Loading