Skip to content

Commit 2ae8852

Browse files
committed
Clean up ENS spec format: remove type field, use deploy overrides
ENS record format is now: { spec: "ERC20", deploy: { symbol: "USDC", decimals: 6 }, circuits: {...} } - Remove type field from EnsSpecEntry, IntentSpec, and ResolvedAddress (it was not derived from the compiler, just made-up metadata) - IntentSpec.deploy replaces the flat decimals/symbol/type fields - Resolver uses deploy.symbol as display name, falls back to contractName - Admin page form no longer has a Type dropdown - loader.ts accepts the new entry format
1 parent b5409b3 commit 2ae8852

6 files changed

Lines changed: 60 additions & 86 deletions

File tree

src/app/clear-signing/admin/page.tsx

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,19 @@ const KNOWN_CONTRACTS = [
2020

2121
const PRESET_SPECS: Record<string, EnsSpecEntry> = {
2222
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": {
23-
specName: "ERC20",
24-
type: "token",
25-
decimals: 6,
26-
symbol: "USDC",
23+
spec: "ERC20",
24+
deploy: { symbol: "USDC", decimals: 6 },
2725
circuits: {
2826
transfer: "7a97aa1eb1a3aa3650a45efe1142ef01f45bf8c3b162c382c33f74bfd21d1435",
2927
approve: "dd2bcbb99a4830637a7ec903932d134e83d094cd2e51e6ffb38cd48e8251ef0f",
3028
},
3129
},
3230
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D": {
33-
specName: "UniswapV2Router",
34-
type: "protocol",
31+
spec: "UniswapV2Router",
3532
},
3633
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": {
37-
specName: "ERC20",
38-
type: "token",
39-
decimals: 18,
40-
symbol: "WETH",
34+
spec: "ERC20",
35+
deploy: { symbol: "WETH", decimals: 18 },
4136
},
4237
};
4338

@@ -54,7 +49,6 @@ export default function AdminPage() {
5449
// Custom entry form
5550
const [customAddr, setCustomAddr] = useState("");
5651
const [customSpecName, setCustomSpecName] = useState("ERC20");
57-
const [customType, setCustomType] = useState<"token" | "protocol">("token");
5852
const [customDecimals, setCustomDecimals] = useState("18");
5953
const [customSymbol, setCustomSymbol] = useState("");
6054

@@ -111,11 +105,12 @@ export default function AdminPage() {
111105
const handleWriteCustom = useCallback(async () => {
112106
if (!provider || !customAddr) return;
113107

108+
const deploy = (customDecimals || customSymbol)
109+
? { decimals: customDecimals ? parseInt(customDecimals) : undefined, symbol: customSymbol || undefined }
110+
: undefined;
114111
const entry: EnsSpecEntry = {
115-
specName: customSpecName,
116-
type: customType,
117-
decimals: customDecimals ? parseInt(customDecimals) : undefined,
118-
symbol: customSymbol || undefined,
112+
spec: customSpecName,
113+
deploy,
119114
};
120115

121116
setTxStatus(`Sending setText for ${customAddr.slice(0, 10)}...`);
@@ -126,7 +121,7 @@ export default function AdminPage() {
126121
} catch (e) {
127122
setTxStatus(`Error: ${e instanceof Error ? e.message : String(e)}`);
128123
}
129-
}, [provider, customAddr, customSpecName, customType, customDecimals, customSymbol, refreshEntries]);
124+
}, [provider, customAddr, customSpecName, customDecimals, customSymbol, refreshEntries]);
130125

131126
return (
132127
<main className="font-serif max-w-[680px] mx-auto px-6 py-20 md:py-32">
@@ -255,19 +250,6 @@ export default function AdminPage() {
255250
<option value="UniswapV2Router">UniswapV2Router</option>
256251
</select>
257252
</div>
258-
<div>
259-
<label className="block text-[12px] text-secondary mb-1">
260-
Type
261-
</label>
262-
<select
263-
value={customType}
264-
onChange={(e) => setCustomType(e.target.value as "token" | "protocol")}
265-
className="w-full text-[13px] px-3 py-2 border border-border rounded bg-white"
266-
>
267-
<option value="token">token</option>
268-
<option value="protocol">protocol</option>
269-
</select>
270-
</div>
271253
</div>
272254
<div className="grid grid-cols-2 gap-3">
273255
<div>

src/app/clear-signing/engine/ens.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,21 @@ import { ethers } from "ethers";
1717
export const ENS_NAME = "veryclear.eth";
1818
const MAINNET_RPC = "https://ethereum-rpc.publicnode.com";
1919

20-
/** Metadata stored in ENS for each registered contract. */
20+
/**
21+
* ENS text record format for a registered contract.
22+
*
23+
* - spec: name of the compiled spec (matches a JSON file in /public/specs/)
24+
* - deploy: per-address overrides (symbol, decimals differ per deployment
25+
* of the same spec, e.g. USDC vs USDT both use ERC20 spec)
26+
* - circuits: SHA-256 hashes of verification keys, keyed by function name,
27+
* pinning the exact circuits compiled from this spec
28+
*/
2129
export type EnsSpecEntry = {
22-
specName: string;
23-
type: "token" | "protocol" | "contract" | "ens";
24-
decimals?: number;
25-
symbol?: string;
26-
/** SHA-256 hashes of verification keys, keyed by function name.
27-
* Pins the exact circuit that was compiled from this spec. */
30+
spec: string;
31+
deploy?: {
32+
symbol?: string;
33+
decimals?: number;
34+
};
2835
circuits?: Record<string, string>;
2936
};
3037

src/app/clear-signing/engine/loader.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,14 @@ function parseParamType(t: string): ParamType {
153153
*
154154
* @param json - The raw JSON from the Verity compiler
155155
* @param address - Contract address (not in the Lean spec, added per-deployment)
156-
* @param meta - Additional metadata (type, decimals, symbol)
156+
* @param entry - ENS registry entry with deploy overrides
157157
*/
158158
export function loadIntentSpec(
159159
json: JsonSpec,
160160
address: string,
161-
meta: { type: "token" | "protocol" | "contract" | "ens"; decimals?: number; symbol?: string }
161+
entry: { spec: string; deploy?: { symbol?: string; decimals?: number }; circuits?: Record<string, string> }
162162
): IntentSpec {
163+
const meta = entry.deploy;
163164
// First, extract constant values for predicate resolution
164165
const constantValues = new Map<string, bigint>();
165166
for (const c of json.constants) {
@@ -201,9 +202,7 @@ export function loadIntentSpec(
201202
return {
202203
contractName: json.contractName,
203204
address,
204-
type: meta.type,
205-
decimals: meta.decimals,
206-
symbol: meta.symbol,
205+
deploy: meta ? { symbol: meta.symbol, decimals: meta.decimals } : undefined,
207206
constants: Object.fromEntries(constantValues),
208207
fns,
209208
bindings,

src/app/clear-signing/engine/resolver.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ export function resolveAddress(address: string): ResolvedAddress | null {
3333
if (!spec) return null;
3434
return {
3535
address: spec.address,
36-
name: spec.contractName,
37-
type: spec.type,
38-
decimals: spec.decimals,
39-
symbol: spec.symbol,
36+
name: spec.deploy?.symbol ?? spec.contractName,
37+
decimals: spec.deploy?.decimals,
38+
symbol: spec.deploy?.symbol,
4039
};
4140
}
4241

src/app/clear-signing/engine/specs.ts

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
* 1. ENS registry (veryclear.eth) — on-chain source of truth
66
* 2. Static fallback — bundled compiler output for offline use
77
*
8-
* The ENS registry maps contract addresses to spec identifiers
9-
* (specName, type, decimals, symbol). The spec AST is loaded from
10-
* static JSON files generated by the Verity compiler.
8+
* ENS records map contract addresses to:
9+
* { spec: "ERC20", deploy: { symbol: "USDC", decimals: 6 }, circuits: {...} }
10+
*
11+
* The spec name points to a compiler-generated JSON in /public/specs/.
1112
*/
1213

1314
import type { IntentSpec } from "./types";
@@ -16,7 +17,7 @@ import { readSpecFromEns, type EnsSpecEntry } from "./ens";
1617
import ERC20_INTENT_JSON from "../../../../public/specs/ERC20.intent.json";
1718
import UNISWAP_V2_INTENT_JSON from "../../../../public/specs/UniswapV2.intent.json";
1819

19-
// ─── Spec JSON index (keyed by specName from ENS) ──────────────────────────
20+
// ─── Spec JSON index (keyed by spec name from ENS) ──────────────────────────
2021

2122
/* eslint-disable @typescript-eslint/no-explicit-any */
2223
const SPEC_JSONS: Record<string, any> = {
@@ -29,31 +30,23 @@ const SPEC_JSONS: Record<string, any> = {
2930

3031
const STATIC_SPECS: Record<string, IntentSpec> = {};
3132

32-
function registerStatic(address: string, specName: string, meta: EnsSpecEntry) {
33-
const json = SPEC_JSONS[specName];
33+
function registerStatic(address: string, entry: EnsSpecEntry) {
34+
const json = SPEC_JSONS[entry.spec];
3435
if (!json) return;
35-
STATIC_SPECS[address.toLowerCase()] = loadIntentSpec(json, address, meta);
36+
STATIC_SPECS[address.toLowerCase()] = loadIntentSpec(json, address, entry);
3637
}
3738

38-
// Pre-register known contracts as fallback
39-
registerStatic("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "ERC20", {
40-
specName: "ERC20", type: "token", decimals: 6, symbol: "USDC",
39+
registerStatic("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", {
40+
spec: "ERC20",
41+
deploy: { symbol: "USDC", decimals: 6 },
4142
});
42-
registerStatic("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", "UniswapV2Router", {
43-
specName: "UniswapV2Router", type: "protocol",
43+
registerStatic("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", {
44+
spec: "UniswapV2Router",
45+
});
46+
registerStatic("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", {
47+
spec: "ERC20",
48+
deploy: { symbol: "WETH", decimals: 18 },
4449
});
45-
46-
// Address-only specs for display resolution
47-
STATIC_SPECS["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"] = {
48-
contractName: "WETH",
49-
address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
50-
type: "token",
51-
decimals: 18,
52-
symbol: "WETH",
53-
constants: {},
54-
fns: [],
55-
bindings: [],
56-
};
5750

5851
export const SPECS = STATIC_SPECS;
5952

@@ -66,16 +59,13 @@ export const SPECS = STATIC_SPECS;
6659
export async function findSpecFromEns(
6760
contractAddress: string
6861
): Promise<IntentSpec | null> {
69-
// Try ENS
7062
const ensEntry = await readSpecFromEns(contractAddress);
7163
if (ensEntry) {
72-
const json = SPEC_JSONS[ensEntry.specName];
64+
const json = SPEC_JSONS[ensEntry.spec];
7365
if (json) {
7466
return loadIntentSpec(json, contractAddress, ensEntry);
7567
}
7668
}
77-
78-
// Fall back to static
7969
return STATIC_SPECS[contractAddress.toLowerCase()] ?? null;
8070
}
8171

src/app/clear-signing/engine/types.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,15 @@ export type Binding = {
125125
* decode any supported function call and produce a human-readable intent.
126126
*/
127127
export type IntentSpec = {
128-
/** Contract name (e.g. "USDC", "Uniswap V2 Router") */
128+
/** Spec name from the compiler (e.g. "ERC20", "UniswapV2Router") */
129129
contractName: string;
130-
/** Ethereum address (checksummed) */
130+
/** Ethereum address this spec is deployed at */
131131
address: string;
132-
/** Display category for the address */
133-
type: "token" | "protocol" | "contract" | "ens";
134-
/** Token decimals (only for tokens) */
135-
decimals?: number;
136-
/** Token symbol (only for tokens) */
137-
symbol?: string;
132+
/** Deployment overrides (symbol, decimals differ per deployment of same spec) */
133+
deploy?: {
134+
symbol?: string;
135+
decimals?: number;
136+
};
138137
/** Named constants used in conditions */
139138
constants: Record<string, bigint>;
140139
/** Intent function declarations */
@@ -176,13 +175,11 @@ export type EmittedTemplate = {
176175
*/
177176
export type ResolvedAddress = {
178177
address: string;
179-
/** Human-readable name from spec's contractName */
178+
/** Display name: deploy.symbol if available, otherwise contractName */
180179
name: string;
181-
/** Category from spec's type field */
182-
type: "token" | "protocol" | "contract" | "ens";
183-
/** Token decimals (only for tokens) */
180+
/** Token decimals from deploy overrides */
184181
decimals?: number;
185-
/** Token symbol (only for tokens) */
182+
/** Token symbol from deploy overrides */
186183
symbol?: string;
187184
};
188185

0 commit comments

Comments
 (0)