Skip to content

Commit a452a37

Browse files
committed
Merge branch 'feat/l2'
2 parents a0d75db + a873a7b commit a452a37

25 files changed

Lines changed: 2467 additions & 576 deletions

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "lib/unruggable-gateways"]
2+
path = lib/unruggable-gateways
3+
url = https://github.com/unruggable-labs/unruggable-gateways

DEPLOYMENT.md

Lines changed: 311 additions & 133 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 156 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
11
# ENS Config Resolver
22

3-
A set of ENS contracts that enable users to claim address-based subnames under your ENS name.
3+
A set of ENS contracts that enable users to claim address-based subnames under your ENS name, with optional L1 → L2 CCIP-Read resolution.
44

55
## Overview
66

7-
This project provides two main contracts:
7+
This project provides three main contracts:
88

99
| Contract | Description |
1010
| --------------------------- | ------------------------------------------------------------------------------------- |
1111
| **ConfigResolver** | A general-purpose ENS resolver for setting records (text, address, contenthash, etc.) |
12-
| **AddressSubnameRegistrar** | Enables users to claim `<their-address>.yourname.eth` subnames |
12+
| **AddressSubnameRegistrar** | Enables users to claim `0x<address>.yourname.eth` subnames |
13+
| **L1ConfigResolver** | Reads L2 ConfigResolver records from L1 via CCIP-Read (Unruggable Gateways) |
14+
15+
## Deployments
16+
17+
### Testnets
18+
19+
| Contract | Network | Address |
20+
| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
21+
| ConfigResolver | Base Sepolia | [`0xA66c55a6b76967477af18A03F2f12d52251Dc2C0`](https://sepolia.basescan.org/address/0xA66c55a6b76967477af18A03F2f12d52251Dc2C0) |
22+
| L1ConfigResolver | Sepolia | [`0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B`](https://sepolia.etherscan.io/address/0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B) |
23+
24+
### Mainnet
25+
26+
| Contract | Network | Address |
27+
| ---------------- | -------- | ------- |
28+
| ConfigResolver | Base | TBD |
29+
| L1ConfigResolver | Ethereum | TBD |
1330

1431
### Example
1532

@@ -37,12 +54,57 @@ forge test
3754

3855
### Deploy
3956

57+
Deploy ConfigResolver + AddressSubnameRegistrar:
58+
4059
```bash
41-
# Deploy to Sepolia
42-
./script/deploy.sh
60+
# Sepolia
61+
PARENT_NODE=$(cast namehash "yourname.eth") \
62+
forge script script/Deploy.s.sol \
63+
--rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
64+
--account deployer \
65+
--broadcast \
66+
--verify
67+
68+
# Mainnet
69+
PARENT_NODE=$(cast namehash "yourname.eth") \
70+
forge script script/Deploy.s.sol \
71+
--rpc-url https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY \
72+
--account deployer \
73+
--broadcast \
74+
--verify
75+
```
4376

44-
# Deploy to Mainnet
45-
./script/deploy.sh mainnet
77+
Deploy ConfigResolver only:
78+
79+
```bash
80+
forge script script/Deploy.s.sol --sig "deployConfigResolver()" \
81+
--rpc-url $RPC_URL \
82+
--account deployer \
83+
--broadcast \
84+
--verify
85+
```
86+
87+
Deploy L1ConfigResolver (for reading L2 records from L1):
88+
89+
```bash
90+
L2_CONFIG_RESOLVER=0x... \
91+
forge script script/Deploy.s.sol --sig "deployL1Resolver()" \
92+
--rpc-url $RPC_URL \
93+
--account deployer \
94+
--broadcast \
95+
--verify
96+
```
97+
98+
Deploy L1 AddressSubnameRegistrar (for L1 claiming with L2 storage):
99+
100+
```bash
101+
PARENT_NODE=$(cast namehash "yourname.eth") \
102+
L1_CONFIG_RESOLVER=0x... \
103+
forge script script/Deploy.s.sol --sig "deployL1Registrar()" \
104+
--rpc-url $RPC_URL \
105+
--account deployer \
106+
--broadcast \
107+
--verify
46108
```
47109

48110
See [DEPLOYMENT.md](./DEPLOYMENT.md) for the full deployment and setup guide.
@@ -90,6 +152,32 @@ registrar.getLabel(addr); // "0x8d25687829d6b85d9e0020b8c89e3ca24de20a89"
90152
registrar.node(addr);
91153
```
92154

155+
### L1ConfigResolver
156+
157+
An L1 resolver that reads ENS records from a ConfigResolver deployed on L2 (Base) using CCIP-Read. Implements the `IL1ConfigResolver` interface.
158+
159+
```solidity
160+
// Supports standard ENS resolution methods
161+
resolver.addr(node); // Get ETH address
162+
resolver.text(node, "url"); // Get text record
163+
resolver.contenthash(node); // Get contenthash
164+
165+
// Also supports ENSIP-10 extended resolution
166+
resolver.resolve(name, data);
167+
168+
// IL1ConfigResolver interface
169+
resolver.l2ChainId(); // Get the L2 chain ID
170+
resolver.l2ConfigResolver(); // Get the L2 ConfigResolver address
171+
```
172+
173+
**Default Verifiers (Base):**
174+
| Network | Verifier | L2 Chain ID |
175+
|---------|----------|-------------|
176+
| Sepolia | `0x7F68510F0fD952184ec0b976De429a29A2Ec0FE3` | 84532 (Base Sepolia) |
177+
| Mainnet | `0x0bC6c539e5fc1fb92F31dE34426f433557A9A5A2` | 8453 (Base) |
178+
179+
Custom verifiers and L2 chain IDs can be specified via environment variables during deployment.
180+
93181
## Development
94182

95183
### Prerequisites
@@ -123,25 +211,68 @@ forge snapshot
123211

124212
## Architecture
125213

214+
### L1 Claiming with L2 Storage (Recommended)
215+
216+
Users claim subnames on L1 (Ethereum) and can change their resolver. Records are stored on L2 (Base) for lower gas costs.
217+
218+
```
219+
┌─────────────────────────────────────────────────────────────────────────┐
220+
│ L1 (Ethereum) │
221+
├─────────────────────────────────────────────────────────────────────────┤
222+
│ │
223+
│ ┌─────────────────────────────┐ ┌───────────────────────────────┐ │
224+
│ │ AddressSubnameRegistrar │ │ L1ConfigResolver │ │
225+
│ │ ───────────────────────── │ │ ─────────────────────────── │ │
226+
│ │ • Users call claim() │────▶│ • Default resolver for │ │
227+
│ │ • Creates ENS node on L1 │ │ claimed subnames │ │
228+
│ │ │ │ • Reads via CCIP-Read │ │
229+
│ └─────────────────────────────┘ └───────────────┬───────────────┘ │
230+
│ │ │
231+
│ User owns ENS node → can change resolver if desired │ │
232+
└───────────────────────────────────────────────────────┼──────────────────┘
233+
│ CCIP-Read
234+
235+
┌─────────────────────────────────────────────────────────────────────────┐
236+
│ L2 (Base) │
237+
├─────────────────────────────────────────────────────────────────────────┤
238+
│ ┌─────────────────────────────────────────────────────────────────┐ │
239+
│ │ ConfigResolver - stores records (text, address, contenthash) │ │
240+
│ └─────────────────────────────────────────────────────────────────┘ │
241+
└─────────────────────────────────────────────────────────────────────────┘
242+
```
243+
244+
**User Flow:**
245+
246+
1. Claim subname on L1 → `registrar.claim()`
247+
2. Set records on L2 → `resolver.setText(node, "url", "https://...")`
248+
3. L1 resolution reads from L2 via CCIP-Read
249+
4. Optionally change resolver on L1 (user owns the ENS node)
250+
251+
### CCIP-Read Flow
252+
126253
```
127-
┌─────────────────────────────────────────────────────────────┐
128-
│ User's Wallet │
129-
└─────────────────────────────────────────────────────────────┘
130-
131-
132-
┌─────────────────────────────────────────────────────────────┐
133-
│ AddressSubnameRegistrar │
134-
│ ┌─────────────────────────────────────────────────────┐ │
135-
│ │ claim() → creates <address>.parent.eth │ │
136-
│ └─────────────────────────────────────────────────────┘ │
137-
└─────────────────────────────────────────────────────────────┘
138-
139-
┌───────────────┴───────────────┐
140-
▼ ▼
141-
┌─────────────────────────┐ ┌─────────────────────────────┐
142-
│ ENS Registry │ │ ConfigResolver │
143-
│ (stores ownership) │ │ (stores records) │
144-
└─────────────────────────┘ └─────────────────────────────┘
254+
┌──────────────────┐ 1. Call ┌─────────────────────┐
255+
│ Your dApp │ ───────────────► │ L1ConfigResolver │
256+
│ (Frontend) │ │ (Ethereum L1) │
257+
└──────────────────┘ └────────┬────────────┘
258+
▲ │
259+
│ 2. Reverts with
260+
│ OffchainLookup
261+
│ │
262+
│ 5. Return ▼
263+
│ verified ┌─────────────────────────────┐
264+
│ data │ Gateway (off-chain) │
265+
│ └─────────────┬───────────────┘
266+
│ │
267+
│ 3. Fetch proofs from L2
268+
│ │
269+
│ ▼
270+
│ ┌─────────────────────────────┐
271+
│ │ ConfigResolver (Base L2) │
272+
│ └─────────────────────────────┘
273+
│ │
274+
│ 4. Return proofs
275+
└─────────────────────────────────┘
145276
```
146277

147278
## License

0 commit comments

Comments
 (0)