diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..e6df966
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lib/unruggable-gateways"]
+ path = lib/unruggable-gateways
+ url = https://github.com/unruggable-labs/unruggable-gateways
diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md
index 4f57df9..cdbad75 100644
--- a/DEPLOYMENT.md
+++ b/DEPLOYMENT.md
@@ -1,13 +1,73 @@
# Deployment & Setup Guide
-This guide walks you through deploying and configuring the `ConfigResolver` and `AddressSubnameRegistrar` contracts.
+This guide walks you through deploying and configuring the `ConfigResolver`, `AddressSubnameRegistrar`, and `L1ConfigResolver` contracts.
## Overview
| Contract | Purpose |
| ------------------------- | --------------------------------------------------------------------- |
| `ConfigResolver` | A general-purpose ENS resolver that allows name owners to set records |
-| `AddressSubnameRegistrar` | Allows users to claim `
.yourname.eth` subnames |
+| `AddressSubnameRegistrar` | Allows users to claim `0x.yourname.eth` subnames |
+| `L1ConfigResolver` | Reads L2 ConfigResolver records from L1 via CCIP-Read |
+
+## Architecture Options
+
+### Option A: L1 Claiming with L2 Storage (Recommended)
+
+Users claim subnames on L1 (Ethereum), but records are stored on L2 (Base) for lower gas costs. Users can optionally change their resolver.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ L1 (Ethereum) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌─────────────────────────────┐ ┌───────────────────────────────┐ │
+│ │ AddressSubnameRegistrar │ │ L1ConfigResolver │ │
+│ │ ───────────────────────── │ │ ─────────────────────────── │ │
+│ │ • Users call claim() │────▶│ • Default resolver for │ │
+│ │ • Creates ENS node on L1 │ │ claimed subnames │ │
+│ │ • Sets resolver to │ │ • Reads records via │ │
+│ │ L1ConfigResolver │ │ CCIP-Read from L2 │ │
+│ └─────────────────────────────┘ └───────────────┬───────────────┘ │
+│ │ │
+│ User owns ENS node → can change resolver if desired │ │
+│ │ │
+└───────────────────────────────────────────────────────┼──────────────────┘
+ │ CCIP-Read
+ ▼
+┌─────────────────────────────────────────────────────────────────────────┐
+│ L2 (Base) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ ConfigResolver │ │
+│ │ ───────────────────────────────────────────────────────────── │ │
+│ │ • Stores text, address, contenthash records │ │
+│ │ • Users set records here (low gas) │ │
+│ │ • Authorizes via reverse node (user's address) │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**User Flow:**
+
+1. User calls `claim()` on L1 `AddressSubnameRegistrar` → creates `0x.parent.eth` in ENS
+2. Subname is created with `L1ConfigResolver` as the resolver
+3. User sets records on L2 `ConfigResolver` (low gas)
+4. L1 resolution reads from L2 via CCIP-Read
+5. User can change their L1 resolver anytime (they own the ENS node)
+
+### Option B: L2-Only with Wildcard Resolution
+
+Simpler setup where everything lives on L2, and L1 uses wildcard resolution. Users cannot change their resolver.
+
+```
+L1: Parent name resolver = L1ConfigResolver (wildcard ENSIP-10)
+L2: ConfigResolver + AddressSubnameRegistrar
+```
+
+**Limitation:** Subnames don't exist in L1 ENS registry, so users cannot change their resolver.
## Prerequisites
@@ -30,126 +90,141 @@ cast wallet list
## Contract Addresses
-### Mainnet
+### ENS Addresses (same on all networks)
| Contract | Address |
| ------------ | -------------------------------------------- |
| ENS Registry | `0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e` |
-| NameWrapper | `0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401` |
+
+### Mainnet
+
+| Contract | Address |
+| ---------------- | -------------------------------------------- |
+| NameWrapper | `0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401` |
+| Gateway Verifier | `0x0bC6c539e5fc1fb92F31dE34426f433557A9A5A2` |
### Sepolia
-| Contract | Address |
-| ------------ | -------------------------------------------- |
-| ENS Registry | `0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e` |
-| NameWrapper | `0x0635513f179D50A207757E05759CbD106d7dFcE8` |
+| Contract | Address |
+| ---------------- | -------------------------------------------- |
+| NameWrapper | `0x0635513f179D50A207757E05759CbD106d7dFcE8` |
+| Gateway Verifier | `0x7F68510F0fD952184ec0b976De429a29A2Ec0FE3` |
---
-## Step 1: Deploy ConfigResolver
+## Step 1: Deploy Contracts
-### Using the deploy script
+### Deploy ConfigResolver + AddressSubnameRegistrar
```bash
-# Deploy to Sepolia (default)
-./script/deploy.sh
+# Sepolia
+PARENT_NODE=$(cast namehash "yourname.eth") \
+ forge script script/Deploy.s.sol \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
-# Deploy to Mainnet
-./script/deploy.sh mainnet
+# Mainnet
+PARENT_NODE=$(cast namehash "yourname.eth") \
+ forge script script/Deploy.s.sol \
+ --rpc-url https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
```
-### Manual deployment
+### Deploy ConfigResolver Only
```bash
-# Set variables
-export RPC_URL="https://sepolia.gateway.tenderly.co"
-export ENS_REGISTRY="0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
-export NAME_WRAPPER="0x0635513f179D50A207757E05759CbD106d7dFcE8"
-
-# Deploy
-forge create src/ConfigResolver.sol:ConfigResolver \
+forge script script/Deploy.s.sol --sig "deployConfigResolver()" \
--rpc-url $RPC_URL \
--account deployer \
- --constructor-args $ENS_REGISTRY $NAME_WRAPPER \
- --verify \
- --etherscan-api-key $ETHERSCAN_API_KEY
+ --broadcast \
+ --verify
```
-Save the deployed address as `CONFIG_RESOLVER`.
-
----
-
-## Step 2: Deploy AddressSubnameRegistrar
+### Deploy L1ConfigResolver (CCIP-Read)
-First, compute the namehash of your parent name:
+For reading L2 records from L1:
```bash
-# Compute namehash for "ethconfig.eth"
-cast namehash "ethconfig.eth"
-# Returns: 0x... (your parent node)
-```
-
-Then deploy:
-
-```bash
-export PARENT_NODE=$(cast namehash "ethconfig.eth")
-export CONFIG_RESOLVER="0x..." # From step 1
-
-forge create src/AddressSubnameRegistrar.sol:AddressSubnameRegistrar \
+L2_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Resolver()" \
--rpc-url $RPC_URL \
--account deployer \
- --constructor-args $ENS_REGISTRY $NAME_WRAPPER $PARENT_NODE $CONFIG_RESOLVER \
- --verify \
- --etherscan-api-key $ETHERSCAN_API_KEY
+ --broadcast \
+ --verify
```
-Save the deployed address as `REGISTRAR`.
-
----
+**Environment Variables:**
-## Step 3: Authorize the Registrar
+| Variable | Required | Default | Description |
+| -------------------- | -------- | ----------------- | ------------------------------- |
+| `L2_CONFIG_RESOLVER` | Yes | - | Address of ConfigResolver on L2 |
+| `VERIFIER` | No | Chain-dependent\* | Gateway verifier address |
+| `L2_CHAIN_ID` | No | Chain-dependent\* | L2 chain ID |
-The registrar needs permission to create subnames. First, check if your name is wrapped.
+\*Defaults: Mainnet → Base (8453) with `0x0bC6c539e5fc1fb92F31dE34426f433557A9A5A2`, Sepolia → Base Sepolia (84532) with `0x7F68510F0fD952184ec0b976De429a29A2Ec0FE3`
-### Check if your name is wrapped
+**Custom L2 deployment (non-Base chains):**
```bash
-# Check who owns the node in ENS Registry
-cast call $ENS_REGISTRY "owner(bytes32)(address)" $PARENT_NODE --rpc-url $RPC_URL
+# Example: Deploy for Arbitrum
+VERIFIER=0x... \
+L2_CHAIN_ID=42161 \
+L2_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Resolver()" \
+ --rpc-url $RPC_URL \
+ --account deployer \
+ --broadcast \
+ --verify
```
-- If the result is the **NameWrapper address** → your name is **wrapped** (Option B)
-- If the result is **your address** → your name is **unwrapped** (Option A)
-
-### Option A: Unwrapped Name
+### Deploy L1 AddressSubnameRegistrar (Option A)
-Transfer ownership of the parent name to the registrar:
+For L1 claiming with L2 storage - deploy after L1ConfigResolver:
```bash
-# Transfer ownership to the registrar
-cast send $ENS_REGISTRY "setOwner(bytes32,address)" \
- $PARENT_NODE \
- $REGISTRAR \
- --rpc-url $RPC_URL \
- --account deployer
+# Sepolia
+PARENT_NODE=$(cast namehash "yourname.eth") \
+L1_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Registrar()" \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+
+# Mainnet
+PARENT_NODE=$(cast namehash "yourname.eth") \
+L1_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Registrar()" \
+ --rpc-url https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
```
-> ⚠️ **Warning**: This transfers full control. Consider using a wrapper or approval instead.
+Save the deployed addresses for the next steps.
+
+---
-### Option B: Wrapped Name (Recommended)
+## Step 2: Authorize the Registrar
-If your name is wrapped in NameWrapper, you need to approve the registrar as an operator.
+The registrar needs permission to create subnames under your wrapped name.
> ⚠️ **Important**: The approval must come from the **actual owner** of the wrapped name, not the deployer (unless they're the same).
-**Step 1: Find the wrapped name owner**
+### Find the wrapped name owner
```bash
+export PARENT_NODE=$(cast namehash "yourname.eth")
+
# Check who owns the wrapped name
cast call $NAME_WRAPPER "ownerOf(uint256)(address)" $PARENT_NODE --rpc-url $RPC_URL
```
-**Step 2: Approve the registrar (from the owner's account)**
+### Approve the registrar
```bash
# Approve registrar to manage your wrapped names
@@ -161,31 +236,14 @@ cast send $NAME_WRAPPER "setApprovalForAll(address,bool)" \
--account # Must be the wrapped name owner
```
-For example, if the owner is in a keystore called `user`:
-
-```bash
-cast send $NAME_WRAPPER "setApprovalForAll(address,bool)" \
- $REGISTRAR \
- true \
- --rpc-url $RPC_URL \
- --account user
-```
-
---
-## Step 4: Enable Wildcard Resolution (ENSIP-10)
+## Step 3: Enable Wildcard Resolution (ENSIP-10)
-The ConfigResolver supports wildcard resolution, allowing `.yourname.eth` to resolve without users needing to claim the subname first. This enables:
-
-- **Address resolution**: `.yourname.eth` automatically resolves to that address
-- **Text records**: Users can set records that resolve via any parent name
+The ConfigResolver supports wildcard resolution, allowing `0x.yourname.eth` to resolve without users needing to claim the subname first.
### Set ConfigResolver as the parent name's resolver
-For wildcard resolution to work, your parent name must use the ConfigResolver as its resolver.
-
-**For wrapped names (NameWrapper):**
-
```bash
# Set ConfigResolver as the resolver for your parent name
# Run this from the wrapped name OWNER's account
@@ -196,16 +254,6 @@ cast send $NAME_WRAPPER "setResolver(bytes32,address)" \
--account
```
-**For unwrapped names (ENS Registry):**
-
-```bash
-cast send $ENS_REGISTRY "setResolver(bytes32,address)" \
- $PARENT_NODE \
- $CONFIG_RESOLVER \
- --rpc-url $RPC_URL \
- --account
-```
-
### Verify wildcard support
```bash
@@ -218,21 +266,9 @@ cast call $ENS_REGISTRY "resolver(bytes32)(address)" $PARENT_NODE --rpc-url $RPC
# Should return: your CONFIG_RESOLVER address
```
-### How it works
-
-Once enabled, any lookup for `.yourname.eth` will:
-
-1. ENS checks if the subname exists → it doesn't (not claimed)
-2. ENS falls back to the parent's resolver (ConfigResolver)
-3. ConfigResolver's `resolve()` function handles the request:
- - For `addr()`: Returns the address from the subdomain label
- - For `text()`: Looks up records stored under the user's reverse node
-
-This means users can set records once (via their reverse node) and have them resolve under any parent name that uses ConfigResolver.
-
---
-## Step 5: Verify Deployment
+## Step 4: Verify Deployment
### Check ConfigResolver
@@ -259,6 +295,23 @@ cast call $REGISTRAR "defaultResolver()" --rpc-url $RPC_URL
cast call $REGISTRAR "available(address)" "0x8d25687829D6b85d9e0020B8c89e3Ca24dE20a89" --rpc-url $RPC_URL
```
+### Check L1ConfigResolver
+
+```bash
+# Verify it supports IExtendedResolver
+cast call $L1_RESOLVER "supportsInterface(bytes4)" "0x9061b923" --rpc-url $RPC_URL
+# Should return: true (0x01)
+
+# Check the L2 chain ID
+cast call $L1_RESOLVER "l2ChainId()(uint256)" --rpc-url $RPC_URL
+
+# Check the L2 target
+cast call $L1_RESOLVER "l2ConfigResolver()(address)" --rpc-url $RPC_URL
+
+# Check the verifier
+cast call $L1_RESOLVER "verifier()(address)" --rpc-url $RPC_URL
+```
+
---
## Usage
@@ -274,7 +327,7 @@ cast send $REGISTRAR "claim()" \
--account user-wallet
```
-This creates `.ethconfig.eth` for the caller.
+This creates `0x.yourname.eth` for the caller (e.g., `0x8d25687829d6b85d9e0020b8c89e3ca24de20a89.yourname.eth`).
### Setting Records on Claimed Subnames
@@ -389,33 +442,35 @@ const hash = await walletClient.writeContract({
## Deployed Contracts
-After deployment, update this section with your addresses:
+### Testnets
+
+| Network | Contract | Address |
+| ------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| Base Sepolia | ConfigResolver | [`0xA66c55a6b76967477af18A03F2f12d52251Dc2C0`](https://sepolia.basescan.org/address/0xA66c55a6b76967477af18A03F2f12d52251Dc2C0) |
+| Sepolia | L1ConfigResolver | [`0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B`](https://sepolia.etherscan.io/address/0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B) |
+
+### Mainnet
-| Network | Contract | Address |
-| ------- | ----------------------- | ------- |
-| Sepolia | ConfigResolver | `0x...` |
-| Sepolia | AddressSubnameRegistrar | `0x...` |
-| Mainnet | ConfigResolver | `0x...` |
-| Mainnet | AddressSubnameRegistrar | `0x...` |
+| Network | Contract | Address |
+| -------- | ---------------- | ------- |
+| Base | ConfigResolver | TBD |
+| Ethereum | L1ConfigResolver | TBD |
---
## Troubleshooting
-### "Unauthorised" error when claiming (wrapped names)
+### "Unauthorised" error when claiming
This is the most common issue. It means the registrar is not approved to create subnames.
**Diagnosis:**
```bash
-# 1. Check if the name is wrapped (owned by NameWrapper in registry)
-cast call $ENS_REGISTRY "owner(bytes32)(address)" $PARENT_NODE --rpc-url $RPC_URL
-
-# 2. If wrapped, find the actual owner
+# 1. Find the wrapped name owner
cast call $NAME_WRAPPER "ownerOf(uint256)(address)" $PARENT_NODE --rpc-url $RPC_URL
-# 3. Check if the registrar is approved by that owner
+# 2. Check if the registrar is approved by that owner
cast call $NAME_WRAPPER "isApprovedForAll(address,address)(bool)" \
\
$REGISTRAR \
@@ -444,7 +499,6 @@ cast send $NAME_WRAPPER "setApprovalForAll(address,bool)" \
### Registrar can't create subnames
-- Ensure the registrar is the owner of the parent node, OR
- Ensure the registrar is approved via NameWrapper **by the wrapped name owner**
### Records not being set
@@ -454,14 +508,138 @@ cast send $NAME_WRAPPER "setApprovalForAll(address,bool)" \
---
-## Security Considerations
+## Full Deployment Workflow (Option A)
+
+This is the complete workflow for deploying the L1 claiming with L2 storage architecture.
+
+### Step 1: Deploy ConfigResolver on L2 (Base)
+
+```bash
+# Base Sepolia
+forge script script/Deploy.s.sol --sig "deployConfigResolver()" \
+ --rpc-url https://base-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+
+# Base Mainnet
+forge script script/Deploy.s.sol --sig "deployConfigResolver()" \
+ --rpc-url https://base-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+```
+
+Save the L2 ConfigResolver address as `L2_CONFIG_RESOLVER`.
+
+### Step 2: Deploy L1ConfigResolver on L1
+
+```bash
+# Sepolia
+L2_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Resolver()" \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+
+# Mainnet
+L2_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Resolver()" \
+ --rpc-url https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+```
+
+Save the L1ConfigResolver address as `L1_CONFIG_RESOLVER`.
+
+### Step 3: Deploy L1 AddressSubnameRegistrar
+
+```bash
+# Sepolia
+PARENT_NODE=$(cast namehash "yourname.eth") \
+L1_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Registrar()" \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+
+# Mainnet
+PARENT_NODE=$(cast namehash "yourname.eth") \
+L1_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Registrar()" \
+ --rpc-url https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+```
+
+Save the L1 AddressSubnameRegistrar address as `L1_REGISTRAR`.
-1. **Parent name ownership**: Once you transfer the parent name to the registrar, you lose direct control. Consider using NameWrapper approvals instead.
+### Step 4: Authorize L1 Registrar
+
+The L1 registrar needs permission to create subnames under your wrapped parent name.
+
+```bash
+# From the wrapped name owner's account
+cast send $NAME_WRAPPER "setApprovalForAll(address,bool)" \
+ $L1_REGISTRAR \
+ true \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account
+```
+
+### Step 5: User Claims on L1
+
+Users can now claim their subname on L1:
+
+```bash
+cast send $L1_REGISTRAR "claim()" \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account user-wallet
+```
+
+### Step 6: User Sets Records on L2
+
+Users set their records on the L2 ConfigResolver:
+
+```bash
+# Get the user's node hash
+USER_NODE=$(cast call $L1_REGISTRAR "node(address)(bytes32)" $USER_ADDRESS \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY)
+
+# Set a text record on L2
+cast send $L2_CONFIG_RESOLVER "setText(bytes32,string,string)" \
+ $USER_NODE \
+ "url" \
+ "https://example.com" \
+ --rpc-url https://base-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account user-wallet
+```
+
+### Step 7: (Optional) User Changes Resolver
+
+Users who want a different resolver can change it on L1 (they own the wrapped subname):
+
+```bash
+# User changes their resolver via NameWrapper
+cast send $NAME_WRAPPER "setResolver(bytes32,address)" \
+ $USER_NODE \
+ $NEW_RESOLVER \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account user-wallet
+```
+
+---
+
+## Security Considerations
-2. **Subname ownership**: Users fully own their claimed subnames and can set any records.
+1. **Subname ownership**: Users fully own their claimed subnames and can set any records.
-3. **No fees**: This implementation doesn't charge fees. Add payment logic if needed.
+2. **No fees**: This implementation doesn't charge fees. Add payment logic if needed.
-4. **No expiry**: Subnames don't expire unless the parent expires. Consider adding reclaim logic.
+3. **No expiry**: Subnames don't expire unless the parent expires. Consider adding reclaim logic.
-5. **Wrapped names**: If the parent is wrapped, subnames will be wrapped too with inherited fuses.
+4. **Wrapped subnames**: Since the parent is wrapped, subnames will be wrapped too with inherited fuses.
diff --git a/README.md b/README.md
index 5d48fa0..e6a1648 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,42 @@
# ENS Config Resolver
-A set of ENS contracts that enable users to claim address-based subnames under your ENS name.
+A set of ENS contracts that enable users to claim address-based subnames under your ENS name, with optional L1 → L2 CCIP-Read resolution.
## Overview
-This project provides two main contracts:
+This project provides three main contracts:
| Contract | Description |
| --------------------------- | ------------------------------------------------------------------------------------- |
| **ConfigResolver** | A general-purpose ENS resolver for setting records (text, address, contenthash, etc.) |
-| **AddressSubnameRegistrar** | Enables users to claim `.yourname.eth` subnames |
+| **AddressSubnameRegistrar** | Enables users to claim `0x.yourname.eth` subnames |
+| **L1ConfigResolver** | Reads L2 ConfigResolver records from L1 via CCIP-Read (Unruggable Gateways) |
+
+## Deployments
+
+### Testnets
+
+| Contract | Network | Address |
+| ---------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- |
+| ConfigResolver | Base Sepolia | [`0xA66c55a6b76967477af18A03F2f12d52251Dc2C0`](https://sepolia.basescan.org/address/0xA66c55a6b76967477af18A03F2f12d52251Dc2C0) |
+| L1ConfigResolver | Sepolia | [`0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B`](https://sepolia.etherscan.io/address/0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B) |
+
+### Mainnet
+
+| Contract | Network | Address |
+| ---------------- | -------- | ------- |
+| ConfigResolver | Base | TBD |
+| L1ConfigResolver | Ethereum | TBD |
### Example
If you own `ethconfig.eth`, users can claim subnames like:
```
-8d25687829d6b85d9e0020b8c89e3ca24de20a89.ethconfig.eth
+0x8d25687829d6b85d9e0020b8c89e3ca24de20a89.ethconfig.eth
```
-The address is normalized to lowercase hex (40 characters, no `0x` prefix).
+The address is normalized to lowercase hex with the `0x` prefix (42 characters total).
## Quick Start
@@ -37,12 +54,57 @@ forge test
### Deploy
+Deploy ConfigResolver + AddressSubnameRegistrar:
+
```bash
-# Deploy to Sepolia
-./script/deploy.sh
+# Sepolia
+PARENT_NODE=$(cast namehash "yourname.eth") \
+ forge script script/Deploy.s.sol \
+ --rpc-url https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+
+# Mainnet
+PARENT_NODE=$(cast namehash "yourname.eth") \
+ forge script script/Deploy.s.sol \
+ --rpc-url https://eth-mainnet.g.alchemy.com/v2/$ALCHEMY_API_KEY \
+ --account deployer \
+ --broadcast \
+ --verify
+```
-# Deploy to Mainnet
-./script/deploy.sh mainnet
+Deploy ConfigResolver only:
+
+```bash
+forge script script/Deploy.s.sol --sig "deployConfigResolver()" \
+ --rpc-url $RPC_URL \
+ --account deployer \
+ --broadcast \
+ --verify
+```
+
+Deploy L1ConfigResolver (for reading L2 records from L1):
+
+```bash
+L2_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Resolver()" \
+ --rpc-url $RPC_URL \
+ --account deployer \
+ --broadcast \
+ --verify
+```
+
+Deploy L1 AddressSubnameRegistrar (for L1 claiming with L2 storage):
+
+```bash
+PARENT_NODE=$(cast namehash "yourname.eth") \
+L1_CONFIG_RESOLVER=0x... \
+ forge script script/Deploy.s.sol --sig "deployL1Registrar()" \
+ --rpc-url $RPC_URL \
+ --account deployer \
+ --broadcast \
+ --verify
```
See [DEPLOYMENT.md](./DEPLOYMENT.md) for the full deployment and setup guide.
@@ -84,12 +146,38 @@ registrar.claimForAddr(addr, owner);
registrar.available(addr);
// Get the label for an address
-registrar.getLabel(addr); // "8d25687829d6b85d9e0020b8c89e3ca24de20a89"
+registrar.getLabel(addr); // "0x8d25687829d6b85d9e0020b8c89e3ca24de20a89"
// Get the node hash
registrar.node(addr);
```
+### L1ConfigResolver
+
+An L1 resolver that reads ENS records from a ConfigResolver deployed on L2 (Base) using CCIP-Read. Implements the `IL1ConfigResolver` interface.
+
+```solidity
+// Supports standard ENS resolution methods
+resolver.addr(node); // Get ETH address
+resolver.text(node, "url"); // Get text record
+resolver.contenthash(node); // Get contenthash
+
+// Also supports ENSIP-10 extended resolution
+resolver.resolve(name, data);
+
+// IL1ConfigResolver interface
+resolver.l2ChainId(); // Get the L2 chain ID
+resolver.l2ConfigResolver(); // Get the L2 ConfigResolver address
+```
+
+**Default Verifiers (Base):**
+| Network | Verifier | L2 Chain ID |
+|---------|----------|-------------|
+| Sepolia | `0x7F68510F0fD952184ec0b976De429a29A2Ec0FE3` | 84532 (Base Sepolia) |
+| Mainnet | `0x0bC6c539e5fc1fb92F31dE34426f433557A9A5A2` | 8453 (Base) |
+
+Custom verifiers and L2 chain IDs can be specified via environment variables during deployment.
+
## Development
### Prerequisites
@@ -123,25 +211,68 @@ forge snapshot
## Architecture
+### L1 Claiming with L2 Storage (Recommended)
+
+Users claim subnames on L1 (Ethereum) and can change their resolver. Records are stored on L2 (Base) for lower gas costs.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ L1 (Ethereum) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌─────────────────────────────┐ ┌───────────────────────────────┐ │
+│ │ AddressSubnameRegistrar │ │ L1ConfigResolver │ │
+│ │ ───────────────────────── │ │ ─────────────────────────── │ │
+│ │ • Users call claim() │────▶│ • Default resolver for │ │
+│ │ • Creates ENS node on L1 │ │ claimed subnames │ │
+│ │ │ │ • Reads via CCIP-Read │ │
+│ └─────────────────────────────┘ └───────────────┬───────────────┘ │
+│ │ │
+│ User owns ENS node → can change resolver if desired │ │
+└───────────────────────────────────────────────────────┼──────────────────┘
+ │ CCIP-Read
+ ▼
+┌─────────────────────────────────────────────────────────────────────────┐
+│ L2 (Base) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ ConfigResolver - stores records (text, address, contenthash) │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**User Flow:**
+
+1. Claim subname on L1 → `registrar.claim()`
+2. Set records on L2 → `resolver.setText(node, "url", "https://...")`
+3. L1 resolution reads from L2 via CCIP-Read
+4. Optionally change resolver on L1 (user owns the ENS node)
+
+### CCIP-Read Flow
+
```
-┌─────────────────────────────────────────────────────────────┐
-│ User's Wallet │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ AddressSubnameRegistrar │
-│ ┌─────────────────────────────────────────────────────┐ │
-│ │ claim() → creates .parent.eth │ │
-│ └─────────────────────────────────────────────────────┘ │
-└─────────────────────────────────────────────────────────────┘
- │
- ┌───────────────┴───────────────┐
- ▼ ▼
-┌─────────────────────────┐ ┌─────────────────────────────┐
-│ ENS Registry │ │ ConfigResolver │
-│ (stores ownership) │ │ (stores records) │
-└─────────────────────────┘ └─────────────────────────────┘
+┌──────────────────┐ 1. Call ┌─────────────────────┐
+│ Your dApp │ ───────────────► │ L1ConfigResolver │
+│ (Frontend) │ │ (Ethereum L1) │
+└──────────────────┘ └────────┬────────────┘
+ ▲ │
+ │ 2. Reverts with
+ │ OffchainLookup
+ │ │
+ │ 5. Return ▼
+ │ verified ┌─────────────────────────────┐
+ │ data │ Gateway (off-chain) │
+ │ └─────────────┬───────────────┘
+ │ │
+ │ 3. Fetch proofs from L2
+ │ │
+ │ ▼
+ │ ┌─────────────────────────────┐
+ │ │ ConfigResolver (Base L2) │
+ │ └─────────────────────────────┘
+ │ │
+ │ 4. Return proofs
+ └─────────────────────────────────┘
```
## License
diff --git a/broadcast/Deploy.s.sol/11155111/deployL1Registrar-latest.json b/broadcast/Deploy.s.sol/11155111/deployL1Registrar-latest.json
new file mode 100644
index 0000000..0156cc9
--- /dev/null
+++ b/broadcast/Deploy.s.sol/11155111/deployL1Registrar-latest.json
@@ -0,0 +1,56 @@
+{
+ "transactions": [
+ {
+ "hash": "0xc643d5af5b42aae00933dd0d76df862b2ea4e14e9c2cd6742c7f5f7f66c924ab",
+ "transactionType": "CREATE",
+ "contractName": "AddressSubnameRegistrar",
+ "contractAddress": "0x8b82d2af30062e0461c8c3bd1a6ced1df650a5e9",
+ "function": null,
+ "arguments": [
+ "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
+ "0x0635513f179D50A207757E05759CbD106d7dFcE8",
+ "0xfd49266f604c6bc93ead36965d74c1cf766a3f0f896faa27a2038a75118625c1",
+ "0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B"
+ ],
+ "transaction": {
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "gas": "0x1a4eae",
+ "value": "0x0",
+ "input": "0x610100604052348015610010575f80fd5b50604051611a10380380611a10833981810160405281019061003291906101e6565b8373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250508160c081815250508073ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff16815250505050505061024a565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61010c826100e3565b9050919050565b5f61011d82610102565b9050919050565b61012d81610113565b8114610137575f80fd5b50565b5f8151905061014881610124565b92915050565b5f61015882610102565b9050919050565b6101688161014e565b8114610172575f80fd5b50565b5f815190506101838161015f565b92915050565b5f819050919050565b61019b81610189565b81146101a5575f80fd5b50565b5f815190506101b681610192565b92915050565b6101c581610102565b81146101cf575f80fd5b50565b5f815190506101e0816101bc565b92915050565b5f805f80608085870312156101fe576101fd6100df565b5b5f61020b8782880161013a565b945050602061021c87828801610175565b935050604061022d878288016101a8565b925050606061023e878288016101d2565b91505092959194509250565b60805160a05160c05160e0516116f261031e5f395f8181610c7201528181610ee60152610fd201525f818161078a01528181610ac201528181610cbb01528181610d1301528181610df901528181610ec30152610faf01525f81816102ea0152818161032a01528181610396015281816108ba015281816108fa0152818161096601528181610b5701528181610b9701528181610c9601528181610dbd0152610e8701525f81816101fb0152818161064e015281816106aa015281816107d601528181610a860152610f7301526116f25ff3fe608060405234801561000f575f80fd5b5060043610610091575f3560e01c80634e71d92d116100645780634e71d92d14610143578063828eab0e14610161578063a8e5fbc01461017f578063bffbe61c1461019d578063f3068a00146101cd57610091565b806310098ad51461009557806328a249b0146100c55780633f15457f146100f55780634709bf4b14610113575b5f80fd5b6100af60048036038101906100aa91906110a1565b6101eb565b6040516100bc91906110e6565b60405180910390f35b6100df60048036038101906100da91906110a1565b610459565b6040516100ec919061116f565b60405180910390f35b6100fd61064c565b60405161010a91906111ea565b60405180910390f35b61012d60048036038101906101289190611203565b610670565b60405161013a9190611259565b60405180910390f35b61014b610c60565b6040516101589190611259565b60405180910390f35b610169610c70565b6040516101769190611281565b60405180910390f35b610187610c94565b60405161019491906112ba565b60405180910390f35b6101b760048036038101906101b291906110a1565b610cb8565b6040516101c49190611259565b60405180910390f35b6101d5610d11565b6040516101e29190611259565b60405180910390f35b5f806101f683610cb8565b90505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be3836040518263ffffffff1660e01b81526004016102529190611259565b602060405180830381865afa15801561026d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061029191906112e7565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102d157600192505050610454565b5f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161415801561037857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561044e575f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b81526004016103ef919061132a565b602060405180830381865afa15801561040a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061042e91906112e7565b73ffffffffffffffffffffffffffffffffffffffff161492505050610454565b5f925050505b919050565b60605f602867ffffffffffffffff81111561047757610476611343565b5b6040519080825280601f01601f1916602001820160405280156104a95781602001600182028036833780820191505090505b5090505f8390505f602890505b5f811115610641578080600190039150507f30313233343536373839616263646566000000000000000000000000000000005f1b600f831673ffffffffffffffffffffffffffffffffffffffff166020811061051557610514611370565b5b1a60f81b60f81c60f81b83828151811061053257610531611370565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060048273ffffffffffffffffffffffffffffffffffffffff16901c91508080600190039150507f30313233343536373839616263646566000000000000000000000000000000005f1b600f831673ffffffffffffffffffffffffffffffffffffffff16602081106105d4576105d3611370565b5b1a60f81b60f81c60f81b8382815181106105f1576105f0611370565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060048273ffffffffffffffffffffffffffffffffffffffff16901c91506104b6565b508192505050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f3373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561074457507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e985e9c584336040518363ffffffff1660e01b815260040161070392919061139d565b602060405180830381865afa15801561071e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061074291906113ee565b155b1561077b576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61078584610d35565b90505f7f0000000000000000000000000000000000000000000000000000000000000000826040516020016107bb929190611439565b6040516020818303038152906040528051906020012090505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be3836040518263ffffffff1660e01b815260040161082d9190611259565b602060405180830381865afa158015610848573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086c91906112e7565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a83575f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161415801561094857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b15610a50575f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b81526004016109bf919061132a565b602060405180830381865afa1580156109da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109fe91906112e7565b73ffffffffffffffffffffffffffffffffffffffff1614610a4b576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a82565b6040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be37f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b8152600401610afd9190611259565b602060405180830381865afa158015610b18573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3c91906112e7565b90505f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1614158015610be557507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b15610bf957610bf48787610dba565b610c04565b610c038487610f71565b5b828773ffffffffffffffffffffffffffffffffffffffff167f1b2af9453f54ccc027b7454c98ebdf2e7bc4b762f1a1c5dd221d1affdb9fe03e88604051610c4b9190611281565b60405180910390a38294505050505092915050565b5f610c6b3333610670565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f7f0000000000000000000000000000000000000000000000000000000000000000610ce383610d35565b604051602001610cf4929190611439565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f60285b5f811115610dae576001810390507f3031323334353637383961626364656600000000000000000000000000000000600f84161a81536010830492506001810390507f3031323334353637383961626364656600000000000000000000000000000000600f84161a8153601083049250610d39565b5060285f209050919050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630178fe3f7f00000000000000000000000000000000000000000000000000000000000000005f1c6040518263ffffffff1660e01b8152600401610e36919061132a565b606060405180830381865afa158015610e51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e7591906114da565b925050505f610e8384610459565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166324c1af447f000000000000000000000000000000000000000000000000000000000000000083867f00000000000000000000000000000000000000000000000000000000000000005f80896040518863ffffffff1660e01b8152600401610f2a97969594939291906115a2565b6020604051808303815f875af1158015610f46573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f6a9190611640565b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635ef2c7f07f000000000000000000000000000000000000000000000000000000000000000084847f00000000000000000000000000000000000000000000000000000000000000005f6040518663ffffffff1660e01b815260040161101295949392919061166b565b5f604051808303815f87803b158015611029575f80fd5b505af115801561103b573d5f803e3d5ffd5b505050505050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61107082611047565b9050919050565b61108081611066565b811461108a575f80fd5b50565b5f8135905061109b81611077565b92915050565b5f602082840312156110b6576110b5611043565b5b5f6110c38482850161108d565b91505092915050565b5f8115159050919050565b6110e0816110cc565b82525050565b5f6020820190506110f95f8301846110d7565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f611141826110ff565b61114b8185611109565b935061115b818560208601611119565b61116481611127565b840191505092915050565b5f6020820190508181035f8301526111878184611137565b905092915050565b5f819050919050565b5f6111b26111ad6111a884611047565b61118f565b611047565b9050919050565b5f6111c382611198565b9050919050565b5f6111d4826111b9565b9050919050565b6111e4816111ca565b82525050565b5f6020820190506111fd5f8301846111db565b92915050565b5f806040838503121561121957611218611043565b5b5f6112268582860161108d565b92505060206112378582860161108d565b9150509250929050565b5f819050919050565b61125381611241565b82525050565b5f60208201905061126c5f83018461124a565b92915050565b61127b81611066565b82525050565b5f6020820190506112945f830184611272565b92915050565b5f6112a4826111b9565b9050919050565b6112b48161129a565b82525050565b5f6020820190506112cd5f8301846112ab565b92915050565b5f815190506112e181611077565b92915050565b5f602082840312156112fc576112fb611043565b5b5f611309848285016112d3565b91505092915050565b5f819050919050565b61132481611312565b82525050565b5f60208201905061133d5f83018461131b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040820190506113b05f830185611272565b6113bd6020830184611272565b9392505050565b6113cd816110cc565b81146113d7575f80fd5b50565b5f815190506113e8816113c4565b92915050565b5f6020828403121561140357611402611043565b5b5f611410848285016113da565b91505092915050565b5f819050919050565b61143361142e82611241565b611419565b82525050565b5f6114448285611422565b6020820191506114548284611422565b6020820191508190509392505050565b5f63ffffffff82169050919050565b61147c81611464565b8114611486575f80fd5b50565b5f8151905061149781611473565b92915050565b5f67ffffffffffffffff82169050919050565b6114b98161149d565b81146114c3575f80fd5b50565b5f815190506114d4816114b0565b92915050565b5f805f606084860312156114f1576114f0611043565b5b5f6114fe868287016112d3565b935050602061150f86828701611489565b9250506040611520868287016114c6565b9150509250925092565b5f819050919050565b5f61154d6115486115438461152a565b61118f565b61149d565b9050919050565b61155d81611533565b82525050565b5f61157d6115786115738461152a565b61118f565b611464565b9050919050565b61158d81611563565b82525050565b61159c8161149d565b82525050565b5f60e0820190506115b55f83018a61124a565b81810360208301526115c78189611137565b90506115d66040830188611272565b6115e36060830187611272565b6115f06080830186611554565b6115fd60a0830185611584565b61160a60c0830184611593565b98975050505050505050565b61161f81611241565b8114611629575f80fd5b50565b5f8151905061163a81611616565b92915050565b5f6020828403121561165557611654611043565b5b5f6116628482850161162c565b91505092915050565b5f60a08201905061167e5f83018861124a565b61168b602083018761124a565b6116986040830186611272565b6116a56060830185611272565b6116b26080830184611554565b969550505050505056fea26469706673582212209d8af90115ac87cd7e89fc6bba07881800c0312acfa22d66dd65718d2e00b17e64736f6c6343000819003300000000000000000000000000000000000c2e074ec69a0dfb2997ba6c7d2e1e0000000000000000000000000635513f179d50a207757e05759cbd106d7dfce8fd49266f604c6bc93ead36965d74c1cf766a3f0f896faa27a2038a75118625c1000000000000000000000000380e926f5d78f21b80a6efef2b3cef9ccc89356b",
+ "nonce": "0x13",
+ "chainId": "0xaa36a7"
+ },
+ "additionalContracts": [],
+ "isFixedGasLimit": false
+ }
+ ],
+ "receipts": [
+ {
+ "status": "0x1",
+ "cumulativeGasUsed": "0xecd1c1",
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "type": "0x2",
+ "transactionHash": "0xc643d5af5b42aae00933dd0d76df862b2ea4e14e9c2cd6742c7f5f7f66c924ab",
+ "transactionIndex": "0x3d",
+ "blockHash": "0x0c13e7c28a4beaf8da7140b25b1d8037eb3b9a009f1b283d80c0dd4bd8f84b00",
+ "blockNumber": "0x9725ae",
+ "gasUsed": "0x143c86",
+ "effectiveGasPrice": "0xa4c8cc",
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "to": null,
+ "contractAddress": "0x8b82d2af30062e0461c8c3bd1a6ced1df650a5e9"
+ }
+ ],
+ "libraries": [],
+ "pending": [],
+ "returns": {
+ "registrar": {
+ "internal_type": "contract AddressSubnameRegistrar",
+ "value": "0x8b82D2aF30062e0461c8C3bd1a6CEd1DF650a5E9"
+ }
+ },
+ "timestamp": 1766581608807,
+ "chain": 11155111,
+ "commit": "c437ed7"
+}
\ No newline at end of file
diff --git a/broadcast/Deploy.s.sol/11155111/deployL1Resolver-latest.json b/broadcast/Deploy.s.sol/11155111/deployL1Resolver-latest.json
new file mode 100644
index 0000000..1839f4e
--- /dev/null
+++ b/broadcast/Deploy.s.sol/11155111/deployL1Resolver-latest.json
@@ -0,0 +1,54 @@
+{
+ "transactions": [
+ {
+ "hash": "0x6225756eafbb061e5389a06964071312993bb716b723ff69e487d9dc0d3299b8",
+ "transactionType": "CREATE",
+ "contractName": "L1ConfigResolver",
+ "contractAddress": "0x380e926f5d78f21b80a6efef2b3cef9ccc89356b",
+ "function": null,
+ "arguments": [
+ "0x7F68510F0fD952184ec0b976De429a29A2Ec0FE3",
+ "0xA66c55a6b76967477af18A03F2f12d52251Dc2C0"
+ ],
+ "transaction": {
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "gas": "0x3e69d6",
+ "value": "0x0",
+ "input": "0x60c060405234801561000f575f80fd5b506040516139b43803806139b483398181016040528101906100319190610139565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050610177565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100cd826100a4565b9050919050565b5f6100de826100c3565b9050919050565b6100ee816100d4565b81146100f8575f80fd5b50565b5f81519050610109816100e5565b92915050565b610118816100c3565b8114610122575f80fd5b50565b5f815190506101338161010f565b92915050565b5f806040838503121561014f5761014e6100a0565b5b5f61015c858286016100fb565b925050602061016d85828601610125565b9150509250929050565b60805160a0516137eb6101c95f395f81816111c6015281816114ae015281816117b40152611acd01525f81816105f8015281816109a701528181610a9f01528181610dc90152610f3b01526137eb5ff3fe608060405234801561000f575f80fd5b50600436106100b2575f3560e01c80637105614d1161006f5780637105614d146101c45780639061b923146101f4578063a52b657e14610224578063bc1c58d114610254578063e31844fe14610284578063e341c27e146102a0576100b2565b806301ffc9a7146100b6578063232826a9146100e65780632b7ac3f3146101165780633026580c146101345780633b3b57de1461016457806359d1d43c14610194575b5f80fd5b6100d060048036038101906100cb91906121a9565b6102be565b6040516100dd91906121ee565b60405180910390f35b61010060048036038101906100fb91906122f3565b61052f565b60405161010d91906123f4565b60405180910390f35b61011e6105f6565b60405161012b919061248e565b60405180910390f35b61014e600480360381019061014991906122f3565b61061a565b60405161015b91906124f9565b60405180910390f35b61017e6004803603810190610179919061254c565b610993565b60405161018b9190612597565b60405180910390f35b6101ae60048036038101906101a99190612605565b610a48565b6040516101bb91906123f4565b60405180910390f35b6101de60048036038101906101d991906122f3565b610b31565b6040516101eb9190612597565b60405180910390f35b61020e60048036038101906102099190612662565b610bb5565b60405161021b91906124f9565b60405180910390f35b61023e600480360381019061023991906122f3565b610e93565b60405161024b91906124f9565b60405180910390f35b61026e6004803603810190610269919061254c565b610f28565b60405161027b91906124f9565b60405180910390f35b61029e60048036038101906102999190612662565b610fcb565b005b6102a86111c4565b6040516102b59190612597565b60405180910390f35b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061038857507f9061b923000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103f057507f3b3b57de000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061045857507ff1cb7e06000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806104c057507f59d1d43c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061052857507fbc1c58d1000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60605f8460ff1614158061056857505f86865f818110610552576105516126e0565b5b90506020028101906105649190612719565b9050145b156105835760405180602001604052805f81525090506105ed565b85855f818110610596576105956126e0565b5b90506020028101906105a89190612719565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505b95945050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60605f8460ff16146106425761063b8383906106369190612791565b6111e8565b905061098a565b5f8383906106509190612791565b9050633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361076e575f87875f8181106106b2576106b16126e0565b5b90506020028101906106c49190612719565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505f815103610739575f6040516020016107219190612597565b6040516020818303038152906040529250505061098a565b806107439061283d565b60601c6040516020016107569190612597565b6040516020818303038152906040529250505061098a565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036108075786865f8181106107cd576107cc6126e0565b5b90506020028101906107df9190612719565b6040516020016107f09291906128dd565b60405160208183030381529060405291505061098a565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036108a05786865f818110610866576108656126e0565b5b90506020028101906108789190612719565b60405160200161088992919061292b565b60405160208183030381529060405291505061098a565b63bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036109395786865f8181106108ff576108fe6126e0565b5b90506020028101906109119190612719565b6040516020016109229291906128dd565b60405160208183030381529060405291505061098a565b5f67ffffffffffffffff8111156109535761095261294d565b5b6040519080825280601f01601f1916602001820160405280156109855781602001600182028036833780820191505090505b509150505b95945050505050565b5f806109a083603c6114a1565b9050610a427f000000000000000000000000000000000000000000000000000000000000000082637105614d60e01b866040516020016109e09190612989565b6040516020818303038152906040525f67ffffffffffffffff811115610a0957610a0861294d565b5b604051908082528060200260200182016040528015610a3c57816020015b6060815260200190600190039081610a275790505b5061159c565b50919050565b60605f610a988585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050506117a7565b9050610b297f00000000000000000000000000000000000000000000000000000000000000008263232826a960e01b60405180602001604052805f8152505f67ffffffffffffffff811115610af057610aef61294d565b5b604051908082528060200260200182016040528015610b2357816020015b6060815260200190600190039081610b0e5790505b5061159c565b509392505050565b5f808460ff16141580610b6957505f86865f818110610b5357610b526126e0565b5b9050602002810190610b659190612719565b9050145b15610b76575f9050610bac565b85855f818110610b8957610b886126e0565b5b9050602002810190610b9b9190612719565b90610ba691906129a2565b60601c90505b95945050505050565b60605f838390610bc59190612791565b90505f633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610c5f575063bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610c8b5784846004908092610c7793929190612a08565b810190610c84919061254c565b9050610db6565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610d015784846004908092610cea93929190612a08565b810190610cf79190612a75565b5080915050610db5565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610d775784846004908092610d6093929190612a08565b810190610d6d9190612ba0565b5080915050610db4565b816040517fa519a14f000000000000000000000000000000000000000000000000000000008152600401610dab9190612c09565b60405180910390fd5b5b5b5f610dc28287876118a2565b9050610e887f000000000000000000000000000000000000000000000000000000000000000082633026580c60e01b89898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050505f67ffffffffffffffff811115610e4f57610e4e61294d565b5b604051908082528060200260200182016040528015610e8257816020015b6060815260200190600190039081610e6d5790505b5061159c565b505050949350505050565b60605f8460ff1614610eb55760405180602001604052805f8152509050610f1f565b85855f818110610ec857610ec76126e0565b5b9050602002810190610eda9190612719565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505b95945050505050565b60605f610f3483611ac0565b9050610fc57f00000000000000000000000000000000000000000000000000000000000000008263a52b657e60e01b60405180602001604052805f8152505f67ffffffffffffffff811115610f8c57610f8b61294d565b5b604051908082528060200260200182016040528015610fbf57816020015b6060815260200190600190039081610faa5790505b5061159c565b50919050565b5f601f858590501614611027575f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050805160208201fd5b5f82828101906110379190612e35565b90505f80825f015173ffffffffffffffffffffffffffffffffffffffff1663e3d1666e846020015185604001518a8a6040518563ffffffff1660e01b81526004016110859493929190612eeb565b5f60405180830381865afa15801561109f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906110c79190613097565b915091505f803073ffffffffffffffffffffffffffffffffffffffff16856060015185858860800151604051602401611102939291906131bb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161116c9190613238565b5f60405180830381855afa9150503d805f81146111a4576040519150601f19603f3d011682016040523d82523d5f602084013e6111a9565b606091505b509150915081156111bc57805160208201f35b805160208201fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6060633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361125d575f6040516020016112479190612597565b604051602081830303815290604052905061149c565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361131c575f67ffffffffffffffff8111156112c3576112c261294d565b5b6040519080825280601f01601f1916602001820160405280156112f55781602001600182028036833780820191505090505b5060405160200161130691906124f9565b604051602081830303815290604052905061149c565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361138d5760405160200161137790613271565b604051602081830303815290604052905061149c565b63bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361144c575f67ffffffffffffffff8111156113f3576113f261294d565b5b6040519080825280601f01601f1916602001820160405280156114255781602001600182028036833780820191505090505b5060405160200161143691906124f9565b604051602081830303815290604052905061149c565b5f67ffffffffffffffff8111156114665761146561294d565b5b6040519080825280601f01601f1916602001820160405280156114985781602001600182028036833780820191505090505b5090505b919050565b6114a9612130565b6114e57f00000000000000000000000000000000000000000000000000000000000000006114d76001611b9d565b611bc690919063ffffffff16565b905061151c611517611512856115045f86611bf190919063ffffffff16565b611c1c90919063ffffffff16565b611c41565b611c64565b9050611532600282611bf190919063ffffffff16565b905061153d81611c41565b905061155a6115558483611c1c90919063ffffffff16565b611c41565b90506115776115728383611c8790919063ffffffff16565b611c41565b90506115945f61158683611d68565b611d8b90919063ffffffff16565b905092915050565b5f8573ffffffffffffffffffffffffffffffffffffffff166387c484fe6040518163ffffffff1660e01b81526004015f60405180830381865afa1580156115e5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061160d919061328f565b90505f82510361168a578573ffffffffffffffffffffffffffffffffffffffff1663b50f2fbc6040518163ffffffff1660e01b81526004015f60405180830381865afa15801561165f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906116879190613422565b91505b3082828760405160240161169f929190613469565b6040516020818303038152906040526331c1980f60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505063e31844fe60e01b6040518060a001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018681526020018a8152602001897bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001888152506040516020016117589190613564565b6040516020818303038152906040526040517f556f183000000000000000000000000000000000000000000000000000000000815260040161179e959493929190613687565b60405180910390fd5b6117af612130565b6117eb7f00000000000000000000000000000000000000000000000000000000000000006117dd6001611b9d565b611bc690919063ffffffff16565b905061182261181d6118188561180a5f86611bf190919063ffffffff16565b611c1c90919063ffffffff16565b611c41565b611c64565b9050611838600a82611bf190919063ffffffff16565b905061184381611c41565b905061186061185b8483611c1c90919063ffffffff16565b611c41565b905061187d6118788383611db990919063ffffffff16565b611c41565b905061189a5f61188c83611d68565b611d8b90919063ffffffff16565b905092915050565b6118aa612130565b5f8383906118b89190612791565b9050633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036119195761191185603c6114a1565b915050611ab9565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361199c575f8484600490809261197993929190612a08565b8101906119869190612a75565b91505061199386826114a1565b92505050611ab9565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611a1f575f848460049080926119fc93929190612a08565b810190611a099190612ba0565b915050611a1686826117a7565b92505050611ab9565b63bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611a7c57611a7485611ac0565b915050611ab9565b806040517fa519a14f000000000000000000000000000000000000000000000000000000008152600401611ab09190612c09565b60405180910390fd5b9392505050565b611ac8612130565b611b047f0000000000000000000000000000000000000000000000000000000000000000611af66001611b9d565b611bc690919063ffffffff16565b9050611b3b611b36611b3184611b235f86611bf190919063ffffffff16565b611c1c90919063ffffffff16565b611c41565b611c64565b9050611b51600382611bf190919063ffffffff16565b9050611b5c81611c41565b9050611b79611b748383611c1c90919063ffffffff16565b611c41565b9050611b965f611b8883611d68565b611d8b90919063ffffffff16565b9050919050565b611ba5612130565b611bbf82611bb1611ddc565b611e4e90919063ffffffff16565b9050919050565b611bce612130565b611be9611be48385611eb690919063ffffffff16565b611eef565b905092915050565b611bf9612130565b611c14611c0f8385611c8790919063ffffffff16565b611f12565b905092915050565b611c24612130565b611c39825f1c84611c8790919063ffffffff16565b905092915050565b611c49612130565b611c5d604883611e4e90919063ffffffff16565b9050919050565b611c6c612130565b611c80603c83611e4e90919063ffffffff16565b9050919050565b611c8f612130565b5f8203611cb057611ca95f84611e4e90919063ffffffff16565b9050611d62565b5f611cba83611f35565b905060038160ff16901b60ff1683901b9250806020611cd9919061371a565b9050611cf9815f611cea919061374e565b85611e4e90919063ffffffff16565b505f845f015190506120008260ff168251611d149190613782565b1115611d4c576040517fec031c1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051848160208401015282810182525084925050505b92915050565b611d70612130565b611d84603d83611e4e90919063ffffffff16565b9050919050565b611d93612130565b611db1611dac8360ff1685611c8790919063ffffffff16565b612028565b905092915050565b611dc1612130565b611dd4828461204b90919063ffffffff16565b905092915050565b611de4612130565b5f61200067ffffffffffffffff811115611e0157611e0061294d565b5b6040519080825280601f01601f191660200182016040528015611e335781602001600182028036833780820191505090505b5090505f815260405180602001604052808281525091505090565b611e56612130565b5f835f015190505f815190506120008110611e9d576040517fec031c1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810182528381602084010153849250505092915050565b611ebe612130565b611ee78273ffffffffffffffffffffffffffffffffffffffff1684611c8790919063ffffffff16565b905092915050565b611ef7612130565b611f0b603283611e4e90919063ffffffff16565b9050919050565b611f1a612130565b611f2e604683611e4e90919063ffffffff16565b9050919050565b5f700100000000000000000000000000000000821015611f5d57608082901b91506010811790505b7801000000000000000000000000000000000000000000000000821015611f8c57604082901b91506008811790505b7c0100000000000000000000000000000000000000000000000000000000821015611fbf57602082901b91506004811790505b7e01000000000000000000000000000000000000000000000000000000000000821015611ff457601082901b91506002811790505b7f0100000000000000000000000000000000000000000000000000000000000000821015612023576001811790505b919050565b612030612130565b612044603383611e4e90919063ffffffff16565b9050919050565b612053612130565b61208c8261207e8451612070602888611e4e90919063ffffffff16565b611c8790919063ffffffff16565b61209490919063ffffffff16565b905092915050565b61209c612130565b5f835f015190506120008351855f0151516120b79190613782565b11156120ef576040517fec031c1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602082010160208401845181015b8082101561211c57815183526020820191506020830192506120ff565b508451835101835250508391505092915050565b6040518060200160405280606081525090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61218881612154565b8114612192575f80fd5b50565b5f813590506121a38161217f565b92915050565b5f602082840312156121be576121bd61214c565b5b5f6121cb84828501612195565b91505092915050565b5f8115159050919050565b6121e8816121d4565b82525050565b5f6020820190506122015f8301846121df565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261222857612227612207565b5b8235905067ffffffffffffffff8111156122455761224461220b565b5b6020830191508360208202830111156122615761226061220f565b5b9250929050565b5f60ff82169050919050565b61227d81612268565b8114612287575f80fd5b50565b5f8135905061229881612274565b92915050565b5f8083601f8401126122b3576122b2612207565b5b8235905067ffffffffffffffff8111156122d0576122cf61220b565b5b6020830191508360018202830111156122ec576122eb61220f565b5b9250929050565b5f805f805f6060868803121561230c5761230b61214c565b5b5f86013567ffffffffffffffff81111561232957612328612150565b5b61233588828901612213565b955095505060206123488882890161228a565b935050604086013567ffffffffffffffff81111561236957612368612150565b5b6123758882890161229e565b92509250509295509295909350565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6123c682612384565b6123d0818561238e565b93506123e081856020860161239e565b6123e9816123ac565b840191505092915050565b5f6020820190508181035f83015261240c81846123bc565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f61245661245161244c84612414565b612433565b612414565b9050919050565b5f6124678261243c565b9050919050565b5f6124788261245d565b9050919050565b6124888161246e565b82525050565b5f6020820190506124a15f83018461247f565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f6124cb826124a7565b6124d581856124b1565b93506124e581856020860161239e565b6124ee816123ac565b840191505092915050565b5f6020820190508181035f83015261251181846124c1565b905092915050565b5f819050919050565b61252b81612519565b8114612535575f80fd5b50565b5f8135905061254681612522565b92915050565b5f602082840312156125615761256061214c565b5b5f61256e84828501612538565b91505092915050565b5f61258182612414565b9050919050565b61259181612577565b82525050565b5f6020820190506125aa5f830184612588565b92915050565b5f8083601f8401126125c5576125c4612207565b5b8235905067ffffffffffffffff8111156125e2576125e161220b565b5b6020830191508360018202830111156125fe576125fd61220f565b5b9250929050565b5f805f6040848603121561261c5761261b61214c565b5b5f61262986828701612538565b935050602084013567ffffffffffffffff81111561264a57612649612150565b5b612656868287016125b0565b92509250509250925092565b5f805f806040858703121561267a5761267961214c565b5b5f85013567ffffffffffffffff81111561269757612696612150565b5b6126a38782880161229e565b9450945050602085013567ffffffffffffffff8111156126c6576126c5612150565b5b6126d28782880161229e565b925092505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f80fd5b5f80fd5b5f80fd5b5f80833560016020038436030381126127355761273461270d565b5b80840192508235915067ffffffffffffffff82111561275757612756612711565b5b60208301925060018202360383131561277357612772612715565b5b509250929050565b5f82905092915050565b5f82821b905092915050565b5f61279c838361277b565b826127a78135612154565b925060048210156127e7576127e27fffffffff0000000000000000000000000000000000000000000000000000000083600403600802612785565b831692505b505092915050565b5f819050602082019050919050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f61283482516127fe565b80915050919050565b5f612847826124a7565b82612851846127ef565b905061285c81612829565b9250601482101561289c576128977fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802612785565b831692505b5050919050565b828183375f83830152505050565b5f6128bc83856124b1565b93506128c98385846128a3565b6128d2836123ac565b840190509392505050565b5f6020820190508181035f8301526128f68184866128b1565b90509392505050565b5f61290a838561238e565b93506129178385846128a3565b612920836123ac565b840190509392505050565b5f6020820190508181035f8301526129448184866128ff565b90509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61298381612519565b82525050565b5f60208201905061299c5f83018461297a565b92915050565b5f6129ad838361277b565b826129b881356127fe565b925060148210156129f8576129f37fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802612785565b831692505b505092915050565b5f80fd5b5f80fd5b5f8085851115612a1b57612a1a612a00565b5b83861115612a2c57612a2b612a04565b5b6001850283019150848603905094509492505050565b5f819050919050565b612a5481612a42565b8114612a5e575f80fd5b50565b5f81359050612a6f81612a4b565b92915050565b5f8060408385031215612a8b57612a8a61214c565b5b5f612a9885828601612538565b9250506020612aa985828601612a61565b9150509250929050565b5f80fd5b612ac0826123ac565b810181811067ffffffffffffffff82111715612adf57612ade61294d565b5b80604052505050565b5f612af1612143565b9050612afd8282612ab7565b919050565b5f67ffffffffffffffff821115612b1c57612b1b61294d565b5b612b25826123ac565b9050602081019050919050565b5f612b44612b3f84612b02565b612ae8565b905082815260208101848484011115612b6057612b5f612ab3565b5b612b6b8482856128a3565b509392505050565b5f82601f830112612b8757612b86612207565b5b8135612b97848260208601612b32565b91505092915050565b5f8060408385031215612bb657612bb561214c565b5b5f612bc385828601612538565b925050602083013567ffffffffffffffff811115612be457612be3612150565b5b612bf085828601612b73565b9150509250929050565b612c0381612154565b82525050565b5f602082019050612c1c5f830184612bfa565b92915050565b5f80fd5b5f80fd5b5f612c3482612577565b9050919050565b612c4481612c2a565b8114612c4e575f80fd5b50565b5f81359050612c5f81612c3b565b92915050565b5f67ffffffffffffffff821115612c7f57612c7e61294d565b5b612c88826123ac565b9050602081019050919050565b5f612ca7612ca284612c65565b612ae8565b905082815260208101848484011115612cc357612cc2612ab3565b5b612cce8482856128a3565b509392505050565b5f82601f830112612cea57612ce9612207565b5b8135612cfa848260208601612c95565b91505092915050565b5f60208284031215612d1857612d17612c22565b5b612d226020612ae8565b90505f82013567ffffffffffffffff811115612d4157612d40612c26565b5b612d4d84828501612cd6565b5f8301525092915050565b5f60a08284031215612d6d57612d6c612c22565b5b612d7760a0612ae8565b90505f612d8684828501612c51565b5f83015250602082013567ffffffffffffffff811115612da957612da8612c26565b5b612db584828501612cd6565b602083015250604082013567ffffffffffffffff811115612dd957612dd8612c26565b5b612de584828501612d03565b6040830152506060612df984828501612195565b606083015250608082013567ffffffffffffffff811115612e1d57612e1c612c26565b5b612e2984828501612cd6565b60808301525092915050565b5f60208284031215612e4a57612e4961214c565b5b5f82013567ffffffffffffffff811115612e6757612e66612150565b5b612e7384828501612d58565b91505092915050565b5f82825260208201905092915050565b5f612e96826124a7565b612ea08185612e7c565b9350612eb081856020860161239e565b612eb9816123ac565b840191505092915050565b5f602083015f8301518482035f860152612ede8282612e8c565b9150508091505092915050565b5f6060820190508181035f830152612f0381876124c1565b90508181036020830152612f178186612ec4565b90508181036040830152612f2c8184866128b1565b905095945050505050565b5f67ffffffffffffffff821115612f5157612f5061294d565b5b602082029050602081019050919050565b5f612f74612f6f84612c65565b612ae8565b905082815260208101848484011115612f9057612f8f612ab3565b5b612f9b84828561239e565b509392505050565b5f82601f830112612fb757612fb6612207565b5b8151612fc7848260208601612f62565b91505092915050565b5f612fe2612fdd84612f37565b612ae8565b905080838252602082019050602084028301858111156130055761300461220f565b5b835b8181101561304c57805167ffffffffffffffff81111561302a57613029612207565b5b8086016130378982612fa3565b85526020850194505050602081019050613007565b5050509392505050565b5f82601f83011261306a57613069612207565b5b815161307a848260208601612fd0565b91505092915050565b5f8151905061309181612274565b92915050565b5f80604083850312156130ad576130ac61214c565b5b5f83015167ffffffffffffffff8111156130ca576130c9612150565b5b6130d685828601613056565b92505060206130e785828601613083565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f6131258383612e8c565b905092915050565b5f602082019050919050565b5f613143826130f1565b61314d81856130fb565b93508360208202850161315f8561310b565b805f5b8581101561319a578484038952815161317b858261311a565b94506131868361312d565b925060208a01995050600181019050613162565b50829750879550505050505092915050565b6131b581612268565b82525050565b5f6060820190508181035f8301526131d38186613139565b90506131e260208301856131ac565b81810360408301526131f481846124c1565b9050949350505050565b5f81905092915050565b5f613212826124a7565b61321c81856131fe565b935061322c81856020860161239e565b80840191505092915050565b5f6132438284613208565b915081905092915050565b50565b5f61325c5f8361238e565b91506132678261324e565b5f82019050919050565b5f6020820190508181035f83015261328881613251565b9050919050565b5f602082840312156132a4576132a361214c565b5b5f82015167ffffffffffffffff8111156132c1576132c0612150565b5b6132cd84828501612fa3565b91505092915050565b5f67ffffffffffffffff8211156132f0576132ef61294d565b5b602082029050602081019050919050565b5f61331361330e84612b02565b612ae8565b90508281526020810184848401111561332f5761332e612ab3565b5b61333a84828561239e565b509392505050565b5f82601f83011261335657613355612207565b5b8151613366848260208601613301565b91505092915050565b5f61338161337c846132d6565b612ae8565b905080838252602082019050602084028301858111156133a4576133a361220f565b5b835b818110156133eb57805167ffffffffffffffff8111156133c9576133c8612207565b5b8086016133d68982613342565b855260208501945050506020810190506133a6565b5050509392505050565b5f82601f83011261340957613408612207565b5b815161341984826020860161336f565b91505092915050565b5f602082840312156134375761343661214c565b5b5f82015167ffffffffffffffff81111561345457613453612150565b5b613460848285016133f5565b91505092915050565b5f6040820190508181035f83015261348181856124c1565b905081810360208301526134958184612ec4565b90509392505050565b6134a78161246e565b82525050565b5f602083015f8301518482035f8601526134c78282612e8c565b9150508091505092915050565b6134dd81612154565b82525050565b5f60a083015f8301516134f85f86018261349e565b50602083015184820360208601526135108282612e8c565b9150506040830151848203604086015261352a82826134ad565b915050606083015161353f60608601826134d4565b50608083015184820360808601526135578282612e8c565b9150508091505092915050565b5f6020820190508181035f83015261357c81846134e3565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f82825260208201905092915050565b5f6135c782612384565b6135d181856135ad565b93506135e181856020860161239e565b6135ea816123ac565b840191505092915050565b5f61360083836135bd565b905092915050565b5f602082019050919050565b5f61361e82613584565b613628818561358e565b93508360208202850161363a8561359e565b805f5b85811015613675578484038952815161365685826135f5565b945061366183613608565b925060208a0199505060018101905061363d565b50829750879550505050505092915050565b5f60a08201905061369a5f830188612588565b81810360208301526136ac8187613614565b905081810360408301526136c081866124c1565b90506136cf6060830185612bfa565b81810360808301526136e181846124c1565b90509695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61372482612268565b915061372f83612268565b9250828203905060ff811115613748576137476136ed565b5b92915050565b5f61375882612268565b915061376383612268565b9250828201905060ff81111561377c5761377b6136ed565b5b92915050565b5f61378c82612a42565b915061379783612a42565b92508282019050808211156137af576137ae6136ed565b5b9291505056fea2646970667358221220fc3387b0a1b580f3ece0e2cdbea2825a1c9f9869d63dc29ded4a4b1ee4d76d3364736f6c634300081900330000000000000000000000007f68510f0fd952184ec0b976de429a29a2ec0fe3000000000000000000000000a66c55a6b76967477af18a03f2f12d52251dc2c0",
+ "nonce": "0x12",
+ "chainId": "0xaa36a7"
+ },
+ "additionalContracts": [],
+ "isFixedGasLimit": false
+ }
+ ],
+ "receipts": [
+ {
+ "status": "0x1",
+ "cumulativeGasUsed": "0x265b371",
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "type": "0x2",
+ "transactionHash": "0x6225756eafbb061e5389a06964071312993bb716b723ff69e487d9dc0d3299b8",
+ "transactionIndex": "0xbd",
+ "blockHash": "0xeafc533b11906cc1da0c5bd3a868639d97a30a1fc34236b4d70f14aa80b2b807",
+ "blockNumber": "0x9724f5",
+ "gasUsed": "0x3002a5",
+ "effectiveGasPrice": "0x22e4b39",
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "to": null,
+ "contractAddress": "0x380e926f5d78f21b80a6efef2b3cef9ccc89356b"
+ }
+ ],
+ "libraries": [],
+ "pending": [],
+ "returns": {
+ "resolver": {
+ "internal_type": "contract L1ConfigResolver",
+ "value": "0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B"
+ }
+ },
+ "timestamp": 1766579077262,
+ "chain": 11155111,
+ "commit": "c437ed7"
+}
\ No newline at end of file
diff --git a/broadcast/Deploy.s.sol/11155111/run-1766579077262.json b/broadcast/Deploy.s.sol/11155111/run-1766579077262.json
new file mode 100644
index 0000000..1839f4e
--- /dev/null
+++ b/broadcast/Deploy.s.sol/11155111/run-1766579077262.json
@@ -0,0 +1,54 @@
+{
+ "transactions": [
+ {
+ "hash": "0x6225756eafbb061e5389a06964071312993bb716b723ff69e487d9dc0d3299b8",
+ "transactionType": "CREATE",
+ "contractName": "L1ConfigResolver",
+ "contractAddress": "0x380e926f5d78f21b80a6efef2b3cef9ccc89356b",
+ "function": null,
+ "arguments": [
+ "0x7F68510F0fD952184ec0b976De429a29A2Ec0FE3",
+ "0xA66c55a6b76967477af18A03F2f12d52251Dc2C0"
+ ],
+ "transaction": {
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "gas": "0x3e69d6",
+ "value": "0x0",
+ "input": "0x60c060405234801561000f575f80fd5b506040516139b43803806139b483398181016040528101906100319190610139565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050610177565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100cd826100a4565b9050919050565b5f6100de826100c3565b9050919050565b6100ee816100d4565b81146100f8575f80fd5b50565b5f81519050610109816100e5565b92915050565b610118816100c3565b8114610122575f80fd5b50565b5f815190506101338161010f565b92915050565b5f806040838503121561014f5761014e6100a0565b5b5f61015c858286016100fb565b925050602061016d85828601610125565b9150509250929050565b60805160a0516137eb6101c95f395f81816111c6015281816114ae015281816117b40152611acd01525f81816105f8015281816109a701528181610a9f01528181610dc90152610f3b01526137eb5ff3fe608060405234801561000f575f80fd5b50600436106100b2575f3560e01c80637105614d1161006f5780637105614d146101c45780639061b923146101f4578063a52b657e14610224578063bc1c58d114610254578063e31844fe14610284578063e341c27e146102a0576100b2565b806301ffc9a7146100b6578063232826a9146100e65780632b7ac3f3146101165780633026580c146101345780633b3b57de1461016457806359d1d43c14610194575b5f80fd5b6100d060048036038101906100cb91906121a9565b6102be565b6040516100dd91906121ee565b60405180910390f35b61010060048036038101906100fb91906122f3565b61052f565b60405161010d91906123f4565b60405180910390f35b61011e6105f6565b60405161012b919061248e565b60405180910390f35b61014e600480360381019061014991906122f3565b61061a565b60405161015b91906124f9565b60405180910390f35b61017e6004803603810190610179919061254c565b610993565b60405161018b9190612597565b60405180910390f35b6101ae60048036038101906101a99190612605565b610a48565b6040516101bb91906123f4565b60405180910390f35b6101de60048036038101906101d991906122f3565b610b31565b6040516101eb9190612597565b60405180910390f35b61020e60048036038101906102099190612662565b610bb5565b60405161021b91906124f9565b60405180910390f35b61023e600480360381019061023991906122f3565b610e93565b60405161024b91906124f9565b60405180910390f35b61026e6004803603810190610269919061254c565b610f28565b60405161027b91906124f9565b60405180910390f35b61029e60048036038101906102999190612662565b610fcb565b005b6102a86111c4565b6040516102b59190612597565b60405180910390f35b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061038857507f9061b923000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103f057507f3b3b57de000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061045857507ff1cb7e06000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806104c057507f59d1d43c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061052857507fbc1c58d1000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60605f8460ff1614158061056857505f86865f818110610552576105516126e0565b5b90506020028101906105649190612719565b9050145b156105835760405180602001604052805f81525090506105ed565b85855f818110610596576105956126e0565b5b90506020028101906105a89190612719565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505b95945050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60605f8460ff16146106425761063b8383906106369190612791565b6111e8565b905061098a565b5f8383906106509190612791565b9050633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361076e575f87875f8181106106b2576106b16126e0565b5b90506020028101906106c49190612719565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505f815103610739575f6040516020016107219190612597565b6040516020818303038152906040529250505061098a565b806107439061283d565b60601c6040516020016107569190612597565b6040516020818303038152906040529250505061098a565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036108075786865f8181106107cd576107cc6126e0565b5b90506020028101906107df9190612719565b6040516020016107f09291906128dd565b60405160208183030381529060405291505061098a565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036108a05786865f818110610866576108656126e0565b5b90506020028101906108789190612719565b60405160200161088992919061292b565b60405160208183030381529060405291505061098a565b63bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036109395786865f8181106108ff576108fe6126e0565b5b90506020028101906109119190612719565b6040516020016109229291906128dd565b60405160208183030381529060405291505061098a565b5f67ffffffffffffffff8111156109535761095261294d565b5b6040519080825280601f01601f1916602001820160405280156109855781602001600182028036833780820191505090505b509150505b95945050505050565b5f806109a083603c6114a1565b9050610a427f000000000000000000000000000000000000000000000000000000000000000082637105614d60e01b866040516020016109e09190612989565b6040516020818303038152906040525f67ffffffffffffffff811115610a0957610a0861294d565b5b604051908082528060200260200182016040528015610a3c57816020015b6060815260200190600190039081610a275790505b5061159c565b50919050565b60605f610a988585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050506117a7565b9050610b297f00000000000000000000000000000000000000000000000000000000000000008263232826a960e01b60405180602001604052805f8152505f67ffffffffffffffff811115610af057610aef61294d565b5b604051908082528060200260200182016040528015610b2357816020015b6060815260200190600190039081610b0e5790505b5061159c565b509392505050565b5f808460ff16141580610b6957505f86865f818110610b5357610b526126e0565b5b9050602002810190610b659190612719565b9050145b15610b76575f9050610bac565b85855f818110610b8957610b886126e0565b5b9050602002810190610b9b9190612719565b90610ba691906129a2565b60601c90505b95945050505050565b60605f838390610bc59190612791565b90505f633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610c5f575063bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610c8b5784846004908092610c7793929190612a08565b810190610c84919061254c565b9050610db6565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610d015784846004908092610cea93929190612a08565b810190610cf79190612a75565b5080915050610db5565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603610d775784846004908092610d6093929190612a08565b810190610d6d9190612ba0565b5080915050610db4565b816040517fa519a14f000000000000000000000000000000000000000000000000000000008152600401610dab9190612c09565b60405180910390fd5b5b5b5f610dc28287876118a2565b9050610e887f000000000000000000000000000000000000000000000000000000000000000082633026580c60e01b89898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050505f67ffffffffffffffff811115610e4f57610e4e61294d565b5b604051908082528060200260200182016040528015610e8257816020015b6060815260200190600190039081610e6d5790505b5061159c565b505050949350505050565b60605f8460ff1614610eb55760405180602001604052805f8152509050610f1f565b85855f818110610ec857610ec76126e0565b5b9050602002810190610eda9190612719565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505b95945050505050565b60605f610f3483611ac0565b9050610fc57f00000000000000000000000000000000000000000000000000000000000000008263a52b657e60e01b60405180602001604052805f8152505f67ffffffffffffffff811115610f8c57610f8b61294d565b5b604051908082528060200260200182016040528015610fbf57816020015b6060815260200190600190039081610faa5790505b5061159c565b50919050565b5f601f858590501614611027575f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050509050805160208201fd5b5f82828101906110379190612e35565b90505f80825f015173ffffffffffffffffffffffffffffffffffffffff1663e3d1666e846020015185604001518a8a6040518563ffffffff1660e01b81526004016110859493929190612eeb565b5f60405180830381865afa15801561109f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906110c79190613097565b915091505f803073ffffffffffffffffffffffffffffffffffffffff16856060015185858860800151604051602401611102939291906131bb565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161116c9190613238565b5f60405180830381855afa9150503d805f81146111a4576040519150601f19603f3d011682016040523d82523d5f602084013e6111a9565b606091505b509150915081156111bc57805160208201f35b805160208201fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6060633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361125d575f6040516020016112479190612597565b604051602081830303815290604052905061149c565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361131c575f67ffffffffffffffff8111156112c3576112c261294d565b5b6040519080825280601f01601f1916602001820160405280156112f55781602001600182028036833780820191505090505b5060405160200161130691906124f9565b604051602081830303815290604052905061149c565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361138d5760405160200161137790613271565b604051602081830303815290604052905061149c565b63bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361144c575f67ffffffffffffffff8111156113f3576113f261294d565b5b6040519080825280601f01601f1916602001820160405280156114255781602001600182028036833780820191505090505b5060405160200161143691906124f9565b604051602081830303815290604052905061149c565b5f67ffffffffffffffff8111156114665761146561294d565b5b6040519080825280601f01601f1916602001820160405280156114985781602001600182028036833780820191505090505b5090505b919050565b6114a9612130565b6114e57f00000000000000000000000000000000000000000000000000000000000000006114d76001611b9d565b611bc690919063ffffffff16565b905061151c611517611512856115045f86611bf190919063ffffffff16565b611c1c90919063ffffffff16565b611c41565b611c64565b9050611532600282611bf190919063ffffffff16565b905061153d81611c41565b905061155a6115558483611c1c90919063ffffffff16565b611c41565b90506115776115728383611c8790919063ffffffff16565b611c41565b90506115945f61158683611d68565b611d8b90919063ffffffff16565b905092915050565b5f8573ffffffffffffffffffffffffffffffffffffffff166387c484fe6040518163ffffffff1660e01b81526004015f60405180830381865afa1580156115e5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061160d919061328f565b90505f82510361168a578573ffffffffffffffffffffffffffffffffffffffff1663b50f2fbc6040518163ffffffff1660e01b81526004015f60405180830381865afa15801561165f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906116879190613422565b91505b3082828760405160240161169f929190613469565b6040516020818303038152906040526331c1980f60e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505063e31844fe60e01b6040518060a001604052808b73ffffffffffffffffffffffffffffffffffffffff1681526020018681526020018a8152602001897bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001888152506040516020016117589190613564565b6040516020818303038152906040526040517f556f183000000000000000000000000000000000000000000000000000000000815260040161179e959493929190613687565b60405180910390fd5b6117af612130565b6117eb7f00000000000000000000000000000000000000000000000000000000000000006117dd6001611b9d565b611bc690919063ffffffff16565b905061182261181d6118188561180a5f86611bf190919063ffffffff16565b611c1c90919063ffffffff16565b611c41565b611c64565b9050611838600a82611bf190919063ffffffff16565b905061184381611c41565b905061186061185b8483611c1c90919063ffffffff16565b611c41565b905061187d6118788383611db990919063ffffffff16565b611c41565b905061189a5f61188c83611d68565b611d8b90919063ffffffff16565b905092915050565b6118aa612130565b5f8383906118b89190612791565b9050633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036119195761191185603c6114a1565b915050611ab9565b63f1cb7e0660e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361199c575f8484600490809261197993929190612a08565b8101906119869190612a75565b91505061199386826114a1565b92505050611ab9565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611a1f575f848460049080926119fc93929190612a08565b810190611a099190612ba0565b915050611a1686826117a7565b92505050611ab9565b63bc1c58d160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611a7c57611a7485611ac0565b915050611ab9565b806040517fa519a14f000000000000000000000000000000000000000000000000000000008152600401611ab09190612c09565b60405180910390fd5b9392505050565b611ac8612130565b611b047f0000000000000000000000000000000000000000000000000000000000000000611af66001611b9d565b611bc690919063ffffffff16565b9050611b3b611b36611b3184611b235f86611bf190919063ffffffff16565b611c1c90919063ffffffff16565b611c41565b611c64565b9050611b51600382611bf190919063ffffffff16565b9050611b5c81611c41565b9050611b79611b748383611c1c90919063ffffffff16565b611c41565b9050611b965f611b8883611d68565b611d8b90919063ffffffff16565b9050919050565b611ba5612130565b611bbf82611bb1611ddc565b611e4e90919063ffffffff16565b9050919050565b611bce612130565b611be9611be48385611eb690919063ffffffff16565b611eef565b905092915050565b611bf9612130565b611c14611c0f8385611c8790919063ffffffff16565b611f12565b905092915050565b611c24612130565b611c39825f1c84611c8790919063ffffffff16565b905092915050565b611c49612130565b611c5d604883611e4e90919063ffffffff16565b9050919050565b611c6c612130565b611c80603c83611e4e90919063ffffffff16565b9050919050565b611c8f612130565b5f8203611cb057611ca95f84611e4e90919063ffffffff16565b9050611d62565b5f611cba83611f35565b905060038160ff16901b60ff1683901b9250806020611cd9919061371a565b9050611cf9815f611cea919061374e565b85611e4e90919063ffffffff16565b505f845f015190506120008260ff168251611d149190613782565b1115611d4c576040517fec031c1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051848160208401015282810182525084925050505b92915050565b611d70612130565b611d84603d83611e4e90919063ffffffff16565b9050919050565b611d93612130565b611db1611dac8360ff1685611c8790919063ffffffff16565b612028565b905092915050565b611dc1612130565b611dd4828461204b90919063ffffffff16565b905092915050565b611de4612130565b5f61200067ffffffffffffffff811115611e0157611e0061294d565b5b6040519080825280601f01601f191660200182016040528015611e335781602001600182028036833780820191505090505b5090505f815260405180602001604052808281525091505090565b611e56612130565b5f835f015190505f815190506120008110611e9d576040517fec031c1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810182528381602084010153849250505092915050565b611ebe612130565b611ee78273ffffffffffffffffffffffffffffffffffffffff1684611c8790919063ffffffff16565b905092915050565b611ef7612130565b611f0b603283611e4e90919063ffffffff16565b9050919050565b611f1a612130565b611f2e604683611e4e90919063ffffffff16565b9050919050565b5f700100000000000000000000000000000000821015611f5d57608082901b91506010811790505b7801000000000000000000000000000000000000000000000000821015611f8c57604082901b91506008811790505b7c0100000000000000000000000000000000000000000000000000000000821015611fbf57602082901b91506004811790505b7e01000000000000000000000000000000000000000000000000000000000000821015611ff457601082901b91506002811790505b7f0100000000000000000000000000000000000000000000000000000000000000821015612023576001811790505b919050565b612030612130565b612044603383611e4e90919063ffffffff16565b9050919050565b612053612130565b61208c8261207e8451612070602888611e4e90919063ffffffff16565b611c8790919063ffffffff16565b61209490919063ffffffff16565b905092915050565b61209c612130565b5f835f015190506120008351855f0151516120b79190613782565b11156120ef576040517fec031c1f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602082010160208401845181015b8082101561211c57815183526020820191506020830192506120ff565b508451835101835250508391505092915050565b6040518060200160405280606081525090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61218881612154565b8114612192575f80fd5b50565b5f813590506121a38161217f565b92915050565b5f602082840312156121be576121bd61214c565b5b5f6121cb84828501612195565b91505092915050565b5f8115159050919050565b6121e8816121d4565b82525050565b5f6020820190506122015f8301846121df565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261222857612227612207565b5b8235905067ffffffffffffffff8111156122455761224461220b565b5b6020830191508360208202830111156122615761226061220f565b5b9250929050565b5f60ff82169050919050565b61227d81612268565b8114612287575f80fd5b50565b5f8135905061229881612274565b92915050565b5f8083601f8401126122b3576122b2612207565b5b8235905067ffffffffffffffff8111156122d0576122cf61220b565b5b6020830191508360018202830111156122ec576122eb61220f565b5b9250929050565b5f805f805f6060868803121561230c5761230b61214c565b5b5f86013567ffffffffffffffff81111561232957612328612150565b5b61233588828901612213565b955095505060206123488882890161228a565b935050604086013567ffffffffffffffff81111561236957612368612150565b5b6123758882890161229e565b92509250509295509295909350565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6123c682612384565b6123d0818561238e565b93506123e081856020860161239e565b6123e9816123ac565b840191505092915050565b5f6020820190508181035f83015261240c81846123bc565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f61245661245161244c84612414565b612433565b612414565b9050919050565b5f6124678261243c565b9050919050565b5f6124788261245d565b9050919050565b6124888161246e565b82525050565b5f6020820190506124a15f83018461247f565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f6124cb826124a7565b6124d581856124b1565b93506124e581856020860161239e565b6124ee816123ac565b840191505092915050565b5f6020820190508181035f83015261251181846124c1565b905092915050565b5f819050919050565b61252b81612519565b8114612535575f80fd5b50565b5f8135905061254681612522565b92915050565b5f602082840312156125615761256061214c565b5b5f61256e84828501612538565b91505092915050565b5f61258182612414565b9050919050565b61259181612577565b82525050565b5f6020820190506125aa5f830184612588565b92915050565b5f8083601f8401126125c5576125c4612207565b5b8235905067ffffffffffffffff8111156125e2576125e161220b565b5b6020830191508360018202830111156125fe576125fd61220f565b5b9250929050565b5f805f6040848603121561261c5761261b61214c565b5b5f61262986828701612538565b935050602084013567ffffffffffffffff81111561264a57612649612150565b5b612656868287016125b0565b92509250509250925092565b5f805f806040858703121561267a5761267961214c565b5b5f85013567ffffffffffffffff81111561269757612696612150565b5b6126a38782880161229e565b9450945050602085013567ffffffffffffffff8111156126c6576126c5612150565b5b6126d28782880161229e565b925092505092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f80fd5b5f80fd5b5f80fd5b5f80833560016020038436030381126127355761273461270d565b5b80840192508235915067ffffffffffffffff82111561275757612756612711565b5b60208301925060018202360383131561277357612772612715565b5b509250929050565b5f82905092915050565b5f82821b905092915050565b5f61279c838361277b565b826127a78135612154565b925060048210156127e7576127e27fffffffff0000000000000000000000000000000000000000000000000000000083600403600802612785565b831692505b505092915050565b5f819050602082019050919050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f61283482516127fe565b80915050919050565b5f612847826124a7565b82612851846127ef565b905061285c81612829565b9250601482101561289c576128977fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802612785565b831692505b5050919050565b828183375f83830152505050565b5f6128bc83856124b1565b93506128c98385846128a3565b6128d2836123ac565b840190509392505050565b5f6020820190508181035f8301526128f68184866128b1565b90509392505050565b5f61290a838561238e565b93506129178385846128a3565b612920836123ac565b840190509392505050565b5f6020820190508181035f8301526129448184866128ff565b90509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61298381612519565b82525050565b5f60208201905061299c5f83018461297a565b92915050565b5f6129ad838361277b565b826129b881356127fe565b925060148210156129f8576129f37fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802612785565b831692505b505092915050565b5f80fd5b5f80fd5b5f8085851115612a1b57612a1a612a00565b5b83861115612a2c57612a2b612a04565b5b6001850283019150848603905094509492505050565b5f819050919050565b612a5481612a42565b8114612a5e575f80fd5b50565b5f81359050612a6f81612a4b565b92915050565b5f8060408385031215612a8b57612a8a61214c565b5b5f612a9885828601612538565b9250506020612aa985828601612a61565b9150509250929050565b5f80fd5b612ac0826123ac565b810181811067ffffffffffffffff82111715612adf57612ade61294d565b5b80604052505050565b5f612af1612143565b9050612afd8282612ab7565b919050565b5f67ffffffffffffffff821115612b1c57612b1b61294d565b5b612b25826123ac565b9050602081019050919050565b5f612b44612b3f84612b02565b612ae8565b905082815260208101848484011115612b6057612b5f612ab3565b5b612b6b8482856128a3565b509392505050565b5f82601f830112612b8757612b86612207565b5b8135612b97848260208601612b32565b91505092915050565b5f8060408385031215612bb657612bb561214c565b5b5f612bc385828601612538565b925050602083013567ffffffffffffffff811115612be457612be3612150565b5b612bf085828601612b73565b9150509250929050565b612c0381612154565b82525050565b5f602082019050612c1c5f830184612bfa565b92915050565b5f80fd5b5f80fd5b5f612c3482612577565b9050919050565b612c4481612c2a565b8114612c4e575f80fd5b50565b5f81359050612c5f81612c3b565b92915050565b5f67ffffffffffffffff821115612c7f57612c7e61294d565b5b612c88826123ac565b9050602081019050919050565b5f612ca7612ca284612c65565b612ae8565b905082815260208101848484011115612cc357612cc2612ab3565b5b612cce8482856128a3565b509392505050565b5f82601f830112612cea57612ce9612207565b5b8135612cfa848260208601612c95565b91505092915050565b5f60208284031215612d1857612d17612c22565b5b612d226020612ae8565b90505f82013567ffffffffffffffff811115612d4157612d40612c26565b5b612d4d84828501612cd6565b5f8301525092915050565b5f60a08284031215612d6d57612d6c612c22565b5b612d7760a0612ae8565b90505f612d8684828501612c51565b5f83015250602082013567ffffffffffffffff811115612da957612da8612c26565b5b612db584828501612cd6565b602083015250604082013567ffffffffffffffff811115612dd957612dd8612c26565b5b612de584828501612d03565b6040830152506060612df984828501612195565b606083015250608082013567ffffffffffffffff811115612e1d57612e1c612c26565b5b612e2984828501612cd6565b60808301525092915050565b5f60208284031215612e4a57612e4961214c565b5b5f82013567ffffffffffffffff811115612e6757612e66612150565b5b612e7384828501612d58565b91505092915050565b5f82825260208201905092915050565b5f612e96826124a7565b612ea08185612e7c565b9350612eb081856020860161239e565b612eb9816123ac565b840191505092915050565b5f602083015f8301518482035f860152612ede8282612e8c565b9150508091505092915050565b5f6060820190508181035f830152612f0381876124c1565b90508181036020830152612f178186612ec4565b90508181036040830152612f2c8184866128b1565b905095945050505050565b5f67ffffffffffffffff821115612f5157612f5061294d565b5b602082029050602081019050919050565b5f612f74612f6f84612c65565b612ae8565b905082815260208101848484011115612f9057612f8f612ab3565b5b612f9b84828561239e565b509392505050565b5f82601f830112612fb757612fb6612207565b5b8151612fc7848260208601612f62565b91505092915050565b5f612fe2612fdd84612f37565b612ae8565b905080838252602082019050602084028301858111156130055761300461220f565b5b835b8181101561304c57805167ffffffffffffffff81111561302a57613029612207565b5b8086016130378982612fa3565b85526020850194505050602081019050613007565b5050509392505050565b5f82601f83011261306a57613069612207565b5b815161307a848260208601612fd0565b91505092915050565b5f8151905061309181612274565b92915050565b5f80604083850312156130ad576130ac61214c565b5b5f83015167ffffffffffffffff8111156130ca576130c9612150565b5b6130d685828601613056565b92505060206130e785828601613083565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f6131258383612e8c565b905092915050565b5f602082019050919050565b5f613143826130f1565b61314d81856130fb565b93508360208202850161315f8561310b565b805f5b8581101561319a578484038952815161317b858261311a565b94506131868361312d565b925060208a01995050600181019050613162565b50829750879550505050505092915050565b6131b581612268565b82525050565b5f6060820190508181035f8301526131d38186613139565b90506131e260208301856131ac565b81810360408301526131f481846124c1565b9050949350505050565b5f81905092915050565b5f613212826124a7565b61321c81856131fe565b935061322c81856020860161239e565b80840191505092915050565b5f6132438284613208565b915081905092915050565b50565b5f61325c5f8361238e565b91506132678261324e565b5f82019050919050565b5f6020820190508181035f83015261328881613251565b9050919050565b5f602082840312156132a4576132a361214c565b5b5f82015167ffffffffffffffff8111156132c1576132c0612150565b5b6132cd84828501612fa3565b91505092915050565b5f67ffffffffffffffff8211156132f0576132ef61294d565b5b602082029050602081019050919050565b5f61331361330e84612b02565b612ae8565b90508281526020810184848401111561332f5761332e612ab3565b5b61333a84828561239e565b509392505050565b5f82601f83011261335657613355612207565b5b8151613366848260208601613301565b91505092915050565b5f61338161337c846132d6565b612ae8565b905080838252602082019050602084028301858111156133a4576133a361220f565b5b835b818110156133eb57805167ffffffffffffffff8111156133c9576133c8612207565b5b8086016133d68982613342565b855260208501945050506020810190506133a6565b5050509392505050565b5f82601f83011261340957613408612207565b5b815161341984826020860161336f565b91505092915050565b5f602082840312156134375761343661214c565b5b5f82015167ffffffffffffffff81111561345457613453612150565b5b613460848285016133f5565b91505092915050565b5f6040820190508181035f83015261348181856124c1565b905081810360208301526134958184612ec4565b90509392505050565b6134a78161246e565b82525050565b5f602083015f8301518482035f8601526134c78282612e8c565b9150508091505092915050565b6134dd81612154565b82525050565b5f60a083015f8301516134f85f86018261349e565b50602083015184820360208601526135108282612e8c565b9150506040830151848203604086015261352a82826134ad565b915050606083015161353f60608601826134d4565b50608083015184820360808601526135578282612e8c565b9150508091505092915050565b5f6020820190508181035f83015261357c81846134e3565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f82825260208201905092915050565b5f6135c782612384565b6135d181856135ad565b93506135e181856020860161239e565b6135ea816123ac565b840191505092915050565b5f61360083836135bd565b905092915050565b5f602082019050919050565b5f61361e82613584565b613628818561358e565b93508360208202850161363a8561359e565b805f5b85811015613675578484038952815161365685826135f5565b945061366183613608565b925060208a0199505060018101905061363d565b50829750879550505050505092915050565b5f60a08201905061369a5f830188612588565b81810360208301526136ac8187613614565b905081810360408301526136c081866124c1565b90506136cf6060830185612bfa565b81810360808301526136e181846124c1565b90509695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61372482612268565b915061372f83612268565b9250828203905060ff811115613748576137476136ed565b5b92915050565b5f61375882612268565b915061376383612268565b9250828201905060ff81111561377c5761377b6136ed565b5b92915050565b5f61378c82612a42565b915061379783612a42565b92508282019050808211156137af576137ae6136ed565b5b9291505056fea2646970667358221220fc3387b0a1b580f3ece0e2cdbea2825a1c9f9869d63dc29ded4a4b1ee4d76d3364736f6c634300081900330000000000000000000000007f68510f0fd952184ec0b976de429a29a2ec0fe3000000000000000000000000a66c55a6b76967477af18a03f2f12d52251dc2c0",
+ "nonce": "0x12",
+ "chainId": "0xaa36a7"
+ },
+ "additionalContracts": [],
+ "isFixedGasLimit": false
+ }
+ ],
+ "receipts": [
+ {
+ "status": "0x1",
+ "cumulativeGasUsed": "0x265b371",
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "type": "0x2",
+ "transactionHash": "0x6225756eafbb061e5389a06964071312993bb716b723ff69e487d9dc0d3299b8",
+ "transactionIndex": "0xbd",
+ "blockHash": "0xeafc533b11906cc1da0c5bd3a868639d97a30a1fc34236b4d70f14aa80b2b807",
+ "blockNumber": "0x9724f5",
+ "gasUsed": "0x3002a5",
+ "effectiveGasPrice": "0x22e4b39",
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "to": null,
+ "contractAddress": "0x380e926f5d78f21b80a6efef2b3cef9ccc89356b"
+ }
+ ],
+ "libraries": [],
+ "pending": [],
+ "returns": {
+ "resolver": {
+ "internal_type": "contract L1ConfigResolver",
+ "value": "0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B"
+ }
+ },
+ "timestamp": 1766579077262,
+ "chain": 11155111,
+ "commit": "c437ed7"
+}
\ No newline at end of file
diff --git a/broadcast/Deploy.s.sol/11155111/run-1766581608807.json b/broadcast/Deploy.s.sol/11155111/run-1766581608807.json
new file mode 100644
index 0000000..0156cc9
--- /dev/null
+++ b/broadcast/Deploy.s.sol/11155111/run-1766581608807.json
@@ -0,0 +1,56 @@
+{
+ "transactions": [
+ {
+ "hash": "0xc643d5af5b42aae00933dd0d76df862b2ea4e14e9c2cd6742c7f5f7f66c924ab",
+ "transactionType": "CREATE",
+ "contractName": "AddressSubnameRegistrar",
+ "contractAddress": "0x8b82d2af30062e0461c8c3bd1a6ced1df650a5e9",
+ "function": null,
+ "arguments": [
+ "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e",
+ "0x0635513f179D50A207757E05759CbD106d7dFcE8",
+ "0xfd49266f604c6bc93ead36965d74c1cf766a3f0f896faa27a2038a75118625c1",
+ "0x380e926f5D78F21b80a6EfeF2B3CEf9CcC89356B"
+ ],
+ "transaction": {
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "gas": "0x1a4eae",
+ "value": "0x0",
+ "input": "0x610100604052348015610010575f80fd5b50604051611a10380380611a10833981810160405281019061003291906101e6565b8373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250508160c081815250508073ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff16815250505050505061024a565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61010c826100e3565b9050919050565b5f61011d82610102565b9050919050565b61012d81610113565b8114610137575f80fd5b50565b5f8151905061014881610124565b92915050565b5f61015882610102565b9050919050565b6101688161014e565b8114610172575f80fd5b50565b5f815190506101838161015f565b92915050565b5f819050919050565b61019b81610189565b81146101a5575f80fd5b50565b5f815190506101b681610192565b92915050565b6101c581610102565b81146101cf575f80fd5b50565b5f815190506101e0816101bc565b92915050565b5f805f80608085870312156101fe576101fd6100df565b5b5f61020b8782880161013a565b945050602061021c87828801610175565b935050604061022d878288016101a8565b925050606061023e878288016101d2565b91505092959194509250565b60805160a05160c05160e0516116f261031e5f395f8181610c7201528181610ee60152610fd201525f818161078a01528181610ac201528181610cbb01528181610d1301528181610df901528181610ec30152610faf01525f81816102ea0152818161032a01528181610396015281816108ba015281816108fa0152818161096601528181610b5701528181610b9701528181610c9601528181610dbd0152610e8701525f81816101fb0152818161064e015281816106aa015281816107d601528181610a860152610f7301526116f25ff3fe608060405234801561000f575f80fd5b5060043610610091575f3560e01c80634e71d92d116100645780634e71d92d14610143578063828eab0e14610161578063a8e5fbc01461017f578063bffbe61c1461019d578063f3068a00146101cd57610091565b806310098ad51461009557806328a249b0146100c55780633f15457f146100f55780634709bf4b14610113575b5f80fd5b6100af60048036038101906100aa91906110a1565b6101eb565b6040516100bc91906110e6565b60405180910390f35b6100df60048036038101906100da91906110a1565b610459565b6040516100ec919061116f565b60405180910390f35b6100fd61064c565b60405161010a91906111ea565b60405180910390f35b61012d60048036038101906101289190611203565b610670565b60405161013a9190611259565b60405180910390f35b61014b610c60565b6040516101589190611259565b60405180910390f35b610169610c70565b6040516101769190611281565b60405180910390f35b610187610c94565b60405161019491906112ba565b60405180910390f35b6101b760048036038101906101b291906110a1565b610cb8565b6040516101c49190611259565b60405180910390f35b6101d5610d11565b6040516101e29190611259565b60405180910390f35b5f806101f683610cb8565b90505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be3836040518263ffffffff1660e01b81526004016102529190611259565b602060405180830381865afa15801561026d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061029191906112e7565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102d157600192505050610454565b5f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161415801561037857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561044e575f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b81526004016103ef919061132a565b602060405180830381865afa15801561040a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061042e91906112e7565b73ffffffffffffffffffffffffffffffffffffffff161492505050610454565b5f925050505b919050565b60605f602867ffffffffffffffff81111561047757610476611343565b5b6040519080825280601f01601f1916602001820160405280156104a95781602001600182028036833780820191505090505b5090505f8390505f602890505b5f811115610641578080600190039150507f30313233343536373839616263646566000000000000000000000000000000005f1b600f831673ffffffffffffffffffffffffffffffffffffffff166020811061051557610514611370565b5b1a60f81b60f81c60f81b83828151811061053257610531611370565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060048273ffffffffffffffffffffffffffffffffffffffff16901c91508080600190039150507f30313233343536373839616263646566000000000000000000000000000000005f1b600f831673ffffffffffffffffffffffffffffffffffffffff16602081106105d4576105d3611370565b5b1a60f81b60f81c60f81b8382815181106105f1576105f0611370565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060048273ffffffffffffffffffffffffffffffffffffffff16901c91506104b6565b508192505050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f3373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561074457507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e985e9c584336040518363ffffffff1660e01b815260040161070392919061139d565b602060405180830381865afa15801561071e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061074291906113ee565b155b1561077b576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61078584610d35565b90505f7f0000000000000000000000000000000000000000000000000000000000000000826040516020016107bb929190611439565b6040516020818303038152906040528051906020012090505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be3836040518263ffffffff1660e01b815260040161082d9190611259565b602060405180830381865afa158015610848573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086c91906112e7565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a83575f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff161415801561094857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b15610a50575f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b81526004016109bf919061132a565b602060405180830381865afa1580156109da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109fe91906112e7565b73ffffffffffffffffffffffffffffffffffffffff1614610a4b576040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a82565b6040517f646cf55800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be37f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b8152600401610afd9190611259565b602060405180830381865afa158015610b18573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b3c91906112e7565b90505f73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1614158015610be557507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b15610bf957610bf48787610dba565b610c04565b610c038487610f71565b5b828773ffffffffffffffffffffffffffffffffffffffff167f1b2af9453f54ccc027b7454c98ebdf2e7bc4b762f1a1c5dd221d1affdb9fe03e88604051610c4b9190611281565b60405180910390a38294505050505092915050565b5f610c6b3333610670565b905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f7f0000000000000000000000000000000000000000000000000000000000000000610ce383610d35565b604051602001610cf4929190611439565b604051602081830303815290604052805190602001209050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f60285b5f811115610dae576001810390507f3031323334353637383961626364656600000000000000000000000000000000600f84161a81536010830492506001810390507f3031323334353637383961626364656600000000000000000000000000000000600f84161a8153601083049250610d39565b5060285f209050919050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630178fe3f7f00000000000000000000000000000000000000000000000000000000000000005f1c6040518263ffffffff1660e01b8152600401610e36919061132a565b606060405180830381865afa158015610e51573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e7591906114da565b925050505f610e8384610459565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166324c1af447f000000000000000000000000000000000000000000000000000000000000000083867f00000000000000000000000000000000000000000000000000000000000000005f80896040518863ffffffff1660e01b8152600401610f2a97969594939291906115a2565b6020604051808303815f875af1158015610f46573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f6a9190611640565b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16635ef2c7f07f000000000000000000000000000000000000000000000000000000000000000084847f00000000000000000000000000000000000000000000000000000000000000005f6040518663ffffffff1660e01b815260040161101295949392919061166b565b5f604051808303815f87803b158015611029575f80fd5b505af115801561103b573d5f803e3d5ffd5b505050505050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61107082611047565b9050919050565b61108081611066565b811461108a575f80fd5b50565b5f8135905061109b81611077565b92915050565b5f602082840312156110b6576110b5611043565b5b5f6110c38482850161108d565b91505092915050565b5f8115159050919050565b6110e0816110cc565b82525050565b5f6020820190506110f95f8301846110d7565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f611141826110ff565b61114b8185611109565b935061115b818560208601611119565b61116481611127565b840191505092915050565b5f6020820190508181035f8301526111878184611137565b905092915050565b5f819050919050565b5f6111b26111ad6111a884611047565b61118f565b611047565b9050919050565b5f6111c382611198565b9050919050565b5f6111d4826111b9565b9050919050565b6111e4816111ca565b82525050565b5f6020820190506111fd5f8301846111db565b92915050565b5f806040838503121561121957611218611043565b5b5f6112268582860161108d565b92505060206112378582860161108d565b9150509250929050565b5f819050919050565b61125381611241565b82525050565b5f60208201905061126c5f83018461124a565b92915050565b61127b81611066565b82525050565b5f6020820190506112945f830184611272565b92915050565b5f6112a4826111b9565b9050919050565b6112b48161129a565b82525050565b5f6020820190506112cd5f8301846112ab565b92915050565b5f815190506112e181611077565b92915050565b5f602082840312156112fc576112fb611043565b5b5f611309848285016112d3565b91505092915050565b5f819050919050565b61132481611312565b82525050565b5f60208201905061133d5f83018461131b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040820190506113b05f830185611272565b6113bd6020830184611272565b9392505050565b6113cd816110cc565b81146113d7575f80fd5b50565b5f815190506113e8816113c4565b92915050565b5f6020828403121561140357611402611043565b5b5f611410848285016113da565b91505092915050565b5f819050919050565b61143361142e82611241565b611419565b82525050565b5f6114448285611422565b6020820191506114548284611422565b6020820191508190509392505050565b5f63ffffffff82169050919050565b61147c81611464565b8114611486575f80fd5b50565b5f8151905061149781611473565b92915050565b5f67ffffffffffffffff82169050919050565b6114b98161149d565b81146114c3575f80fd5b50565b5f815190506114d4816114b0565b92915050565b5f805f606084860312156114f1576114f0611043565b5b5f6114fe868287016112d3565b935050602061150f86828701611489565b9250506040611520868287016114c6565b9150509250925092565b5f819050919050565b5f61154d6115486115438461152a565b61118f565b61149d565b9050919050565b61155d81611533565b82525050565b5f61157d6115786115738461152a565b61118f565b611464565b9050919050565b61158d81611563565b82525050565b61159c8161149d565b82525050565b5f60e0820190506115b55f83018a61124a565b81810360208301526115c78189611137565b90506115d66040830188611272565b6115e36060830187611272565b6115f06080830186611554565b6115fd60a0830185611584565b61160a60c0830184611593565b98975050505050505050565b61161f81611241565b8114611629575f80fd5b50565b5f8151905061163a81611616565b92915050565b5f6020828403121561165557611654611043565b5b5f6116628482850161162c565b91505092915050565b5f60a08201905061167e5f83018861124a565b61168b602083018761124a565b6116986040830186611272565b6116a56060830185611272565b6116b26080830184611554565b969550505050505056fea26469706673582212209d8af90115ac87cd7e89fc6bba07881800c0312acfa22d66dd65718d2e00b17e64736f6c6343000819003300000000000000000000000000000000000c2e074ec69a0dfb2997ba6c7d2e1e0000000000000000000000000635513f179d50a207757e05759cbd106d7dfce8fd49266f604c6bc93ead36965d74c1cf766a3f0f896faa27a2038a75118625c1000000000000000000000000380e926f5d78f21b80a6efef2b3cef9ccc89356b",
+ "nonce": "0x13",
+ "chainId": "0xaa36a7"
+ },
+ "additionalContracts": [],
+ "isFixedGasLimit": false
+ }
+ ],
+ "receipts": [
+ {
+ "status": "0x1",
+ "cumulativeGasUsed": "0xecd1c1",
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "type": "0x2",
+ "transactionHash": "0xc643d5af5b42aae00933dd0d76df862b2ea4e14e9c2cd6742c7f5f7f66c924ab",
+ "transactionIndex": "0x3d",
+ "blockHash": "0x0c13e7c28a4beaf8da7140b25b1d8037eb3b9a009f1b283d80c0dd4bd8f84b00",
+ "blockNumber": "0x9725ae",
+ "gasUsed": "0x143c86",
+ "effectiveGasPrice": "0xa4c8cc",
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "to": null,
+ "contractAddress": "0x8b82d2af30062e0461c8c3bd1a6ced1df650a5e9"
+ }
+ ],
+ "libraries": [],
+ "pending": [],
+ "returns": {
+ "registrar": {
+ "internal_type": "contract AddressSubnameRegistrar",
+ "value": "0x8b82D2aF30062e0461c8C3bd1a6CEd1DF650a5E9"
+ }
+ },
+ "timestamp": 1766581608807,
+ "chain": 11155111,
+ "commit": "c437ed7"
+}
\ No newline at end of file
diff --git a/broadcast/Deploy.s.sol/84532/deployConfigResolver-latest.json b/broadcast/Deploy.s.sol/84532/deployConfigResolver-latest.json
new file mode 100644
index 0000000..a69a2af
--- /dev/null
+++ b/broadcast/Deploy.s.sol/84532/deployConfigResolver-latest.json
@@ -0,0 +1,62 @@
+{
+ "transactions": [
+ {
+ "hash": "0x5349252e11494c3eb04faefde3b94b6a7e8abb41a89af880771ff6ac3bf7882d",
+ "transactionType": "CREATE",
+ "contractName": "ConfigResolver",
+ "contractAddress": "0xa66c55a6b76967477af18a03f2f12d52251dc2c0",
+ "function": null,
+ "arguments": [
+ "0x0000000000000000000000000000000000000000",
+ "0x0000000000000000000000000000000000000000"
+ ],
+ "transaction": {
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "gas": "0x68a33f",
+ "value": "0x0",
+ "input": "0x60c060405234801561000f575f80fd5b5060405161601e38038061601e8339818101604052810190610031919061014a565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050610188565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100cd826100a4565b9050919050565b5f6100de826100c3565b9050919050565b6100ee816100d4565b81146100f8575f80fd5b50565b5f81519050610109816100e5565b92915050565b5f610119826100c3565b9050919050565b6101298161010f565b8114610133575f80fd5b50565b5f8151905061014481610120565b92915050565b5f80604083850312156101605761015f6100a0565b5b5f61016d858286016100fb565b925050602061017e85828601610136565b9150509250929050565b60805160a051615e6e6101b05f395f8181612bcc0152612c1f01525f612b320152615e6e5ff3fe608060405234801561000f575f80fd5b50600436106101f9575f3560e01c80637737221311610118578063bc1c58d1116100ab578063d700ff331161007a578063d700ff331461064f578063e32954eb1461067f578063e59d895d146106af578063e985e9c5146106cb578063f1cb7e06146106fb576101f9565b8063bc1c58d1146105b6578063c8690233146105e6578063ce3decdc14610617578063d5fa2b0014610633576101f9565b8063a4b91a01116100e7578063a4b91a011461050a578063a8fa568214610526578063a9784b3e14610556578063ac9650d814610586576101f9565b806377372213146104865780638b95dd71146104a25780639061b923146104be578063a22cb465146104ee576101f9565b80633603d758116101905780635c98042b1161015f5780635c98042b146103da578063623195b01461040a578063691f3431146104265780637315937d14610456576101f9565b80633603d7581461032e5780633b3b57de1461034a5780634cbf6ba41461037a57806359d1d43c146103aa576101f9565b80632203ab56116101cc5780632203ab561461029557806329cd62ea146102c6578063304e6ade146102e257806332f111d7146102fe576101f9565b806301ffc9a7146101fd5780630af179d71461022d57806310f13a8c14610249578063124a319c14610265575b5f80fd5b61021760048036038101906102129190613f96565b61072b565b6040516102249190613fdb565b60405180910390f35b61024760048036038101906102429190614088565b61076c565b005b610263600480360381019061025e919061413a565b6109bb565b005b61027f600480360381019061027a91906141cb565b610ab0565b60405161028c9190614248565b60405180910390f35b6102af60048036038101906102aa9190614294565b610ef1565b6040516102bd929190614351565b60405180910390f35b6102e060048036038101906102db919061437f565b61106a565b005b6102fc60048036038101906102f79190614088565b61113d565b005b61031860048036038101906103139190614294565b6111f6565b6040516103259190613fdb565b60405180910390f35b610348600480360381019061034391906143cf565b611274565b005b610364600480360381019061035f91906143cf565b61133f565b604051610371919061441a565b60405180910390f35b610394600480360381019061038f9190614433565b61135e565b6040516103a19190613fdb565b60405180910390f35b6103c460048036038101906103bf9190614471565b6113e2565b6040516103d19190614520565b60405180910390f35b6103f460048036038101906103ef91906143cf565b6114e9565b6040516104019190614540565b60405180910390f35b610424600480360381019061041f9190614560565b6115d0565b005b610440600480360381019061043b91906143cf565b6116a6565b60405161044d9190614520565b60405180910390f35b610470600480360381019061046b91906145fb565b61178d565b60405161047d9190614635565b60405180910390f35b6104a0600480360381019061049b9190614471565b611861565b005b6104bc60048036038101906104b79190614776565b61191a565b005b6104d860048036038101906104d391906147e2565b611a93565b6040516104e59190614540565b60405180910390f35b6105086004803603810190610503919061488a565b611ef1565b005b610524600480360381019061051f91906148c8565b612057565b005b610540600480360381019061053b919061494f565b6121ba565b60405161054d9190614540565b60405180910390f35b610570600480360381019061056b919061499f565b6122c9565b60405161057d9190613fdb565b60405180910390f35b6105a0600480360381019061059b9190614a44565b612367565b6040516105ad9190614b92565b60405180910390f35b6105d060048036038101906105cb91906143cf565b61237e565b6040516105dd9190614540565b60405180910390f35b61060060048036038101906105fb91906143cf565b612465565b60405161060e929190614bb2565b60405180910390f35b610631600480360381019061062c9190614088565b612507565b005b61064d60048036038101906106489190614bd9565b612686565b005b610669600480360381019061066491906143cf565b6126c8565b6040516106769190614c39565b60405180910390f35b61069960048036038101906106949190614c52565b6126eb565b6040516106a69190614b92565b60405180910390f35b6106c960048036038101906106c49190614caf565b612701565b005b6106e560048036038101906106e09190614cff565b612853565b6040516106f29190613fdb565b60405180910390f35b61071560048036038101906107109190614294565b6128e1565b6040516107229190614540565b60405180910390f35b5f639061b92360e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610765575061076482612a9d565b5b9050919050565b8261077681612b16565b61077e575f80fd5b5f806060805f805f808b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f6108025f8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612d1590919063ffffffff16565b90505b61080e81612d3e565b610940575f8761ffff1603610868578060400151965061082d81612d52565b9450846040516020016108409190614d77565b60405160208183030381529060405280519060200120925061086181612d87565b9350610932565b5f61087282612d52565b9050816040015161ffff168861ffff1614158061089f575061089d8187612dbf90919063ffffffff16565b155b15610930576109098c878a8e8e8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050508b8c88602001516108ff9190614dba565b5f8c51148a612de6565b81604001519750816020015196508095508580519060200120935061092d82612d87565b94505b505b61093b81613136565b610805565b505f845111156109af576109ae8a85888c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050898a8f8f90506109a49190614dba565b5f8a511488612de6565b5b50505050505050505050565b846109c581612b16565b6109cd575f80fd5b8282600a5f805f8b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f208787604051610a36929190614e1b565b90815260200160405180910390209182610a51929190615037565b508484604051610a62929190614e1b565b6040518091039020867f448bc014f1536726cf8d54ff3d6481ed3cbc683c2591ca204274009afa09b1a187878787604051610aa09493929190615130565b60405180910390a3505050505050565b5f8060075f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610bb45780915050610eeb565b5f610bbe8561133f565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610bfd575f92505050610eeb565b5f808273ffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000604051602401610c479190615178565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610cd19190614d77565b5f60405180830381855afa9150503d805f8114610d09576040519150601f19603f3d011682016040523d82523d5f602084013e610d0e565b606091505b5091509150811580610d21575060208151105b80610d6e57505f60f81b81601f81518110610d3f57610d3e615191565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610d7f575f945050505050610eeb565b8273ffffffffffffffffffffffffffffffffffffffff1686604051602401610da79190615178565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610e319190614d77565b5f60405180830381855afa9150503d805f8114610e69576040519150601f19603f3d011682016040523d82523d5f602084013e610e6e565b606091505b508092508193505050811580610e85575060208151105b80610ed257505f60f81b81601f81518110610ea357610ea2615191565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610ee3575f945050505050610eeb565b829450505050505b92915050565b5f60605f60015f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f2090505f600190505b5f81118015610f635750848111155b1561104c575f85821614158015610f9557505f825f8381526020019081526020015f208054610f9190614e6a565b9050115b156110405780825f8381526020019081526020015f20808054610fb790614e6a565b80601f0160208091040260200160405190810160405280929190818152602001828054610fe390614e6a565b801561102e5780601f106110055761010080835404028352916020019161102e565b820191905f5260205f20905b81548152906001019060200180831161101157829003601f168201915b50505050509050935093505050611063565b600181901b9050610f54565b505f60405180602001604052805f81525092509250505b9250929050565b8261107481612b16565b61107c575f80fd5b60405180604001604052808481526020018381525060095f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f820151815f015560208201518160010155905050837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46848460405161112f929190614bb2565b60405180910390a250505050565b8261114781612b16565b61114f575f80fd5b828260035f805f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f2091826111b5929190615220565b50837fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d757884846040516111e8929190615319565b60405180910390a250505050565b5f8060025f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f20805461126990614e6a565b905011905092915050565b8061127e81612b16565b611286575f80fd5b5f808381526020019081526020015f205f81819054906101000a900467ffffffffffffffff16809291906112b99061533b565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050817fc6621ccb8f3f5a04bb6502154b2caf6adf5983fe76dfef1cfc9c42e3579db4445f808581526020019081526020015f205f9054906101000a900467ffffffffffffffff166040516113339190614c39565b60405180910390a25050565b5f61134b82603c6128e1565b611354906153b8565b60601c9050919050565b5f8060065f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f9054906101000a900461ffff1661ffff161415905092915050565b6060600a5f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f20838360405161144b929190614e1b565b9081526020016040518091039020805461146490614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461149090614e6a565b80156114db5780601f106114b2576101008083540402835291602001916114db565b820191905f5260205f20905b8154815290600101906020018083116114be57829003601f168201915b505050505090509392505050565b606060045f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f20805461154d90614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461157990614e6a565b80156115c45780601f1061159b576101008083540402835291602001916115c4565b820191905f5260205f20905b8154815290600101906020018083116115a757829003601f168201915b50505050509050919050565b836115da81612b16565b6115e2575f80fd5b5f846001866115f19190614dba565b16146115fb575f80fd5b828260015f805f8a81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8881526020019081526020015f205f8781526020019081526020015f209182611670929190615220565b5083857faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a35050505050565b606060085f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f20805461170a90614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461173690614e6a565b80156117815780601f1061175857610100808354040283529160200191611781565b820191905f5260205f20905b81548152906001019060200180831161176457829003601f168201915b50505050509050919050565b5f8060285b5f811115611807576001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a81536010840493506001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a8153601084049350611792565b5060285f2090507f91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e25f1b8160405160200161184392919061543e565b60405160208183030381529060405280519060200120915050919050565b8261186b81612b16565b611873575f80fd5b828260085f805f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f2091826118d9929190615037565b50837fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7848460405161190c929190615469565b60405180910390a250505050565b8261192481612b16565b61192c575f80fd5b5f82511415801561193f57506014825114155b8015611950575061194f83613274565b5b1561199257816040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016119899190614540565b60405180910390fd5b837f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af75284846040516119c4929190614351565b60405180910390a2603c8303611a1957837f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd283611a00906153b8565b60601c604051611a109190614248565b60405180910390a25b8160025f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f8581526020019081526020015f209081611a8c919061548b565b5050505050565b60605f85855f818110611aa957611aa8615191565b5b9050013560f81c60f81b60f81c60ff16905060288103611e32575f8686600190602992611ad893929190615562565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505f80611b345f60288561329b9092919063ffffffff16565b9150915080611b78576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b6f906155e6565b60405180910390fd5b5f611b828361178d565b90505f88885f90600492611b9893929190615562565b90611ba39190615604565b9050633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611c1e5783604051602001611c029190614248565b6040516020818303038152906040529650505050505050611ee9565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611d3d575f89896004908092611c7e93929190615562565b810190611c8b9190615700565b9150505f3073ffffffffffffffffffffffffffffffffffffffff166359d1d43c85846040518363ffffffff1660e01b8152600401611cca92919061575a565b5f60405180830381865afa158015611ce4573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611d0c91906157f6565b905080604051602001611d1f9190614520565b60405160208183030381529060405298505050505050505050611ee9565b5f81838b8b6024908092611d5393929190615562565b604051602001611d669493929190615881565b60405160208183030381529060405290505f803073ffffffffffffffffffffffffffffffffffffffff1683604051611d9e9190614d77565b5f60405180830381855afa9150503d805f8114611dd6576040519150601f19603f3d011682016040523d82523d5f602084013e611ddb565b606091505b50915091508115611df757809950505050505050505050611ee9565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e2990615905565b60405180910390fd5b5f803073ffffffffffffffffffffffffffffffffffffffff168686604051611e5b929190615923565b5f60405180830381855afa9150503d805f8114611e93576040519150601f19603f3d011682016040523d82523d5f602084013e611e98565b606091505b50915091508115611eae57809350505050611ee9565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee090615985565b60405180910390fd5b949350505050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603611f5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f5690615a13565b60405180910390fd5b80600b5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405161204b9190613fdb565b60405180910390a35050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036120c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120bc90615a7b565b60405180910390fd5b80600c5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508015158273ffffffffffffffffffffffffffffffffffffffff16847ff0ddb3b04746704017f9aa8bd728fcc2c1d11675041205350018915f5e4750a0336040516121ad9190614248565b60405180910390a4505050565b606060055f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f8361ffff1661ffff1681526020019081526020015f20805461224490614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461227090614e6a565b80156122bb5780601f10612292576101008083540402835291602001916122bb565b820191905f5260205f20905b81548152906001019060200180831161229e57829003601f168201915b505050505090509392505050565b5f600c5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1690509392505050565b60606123765f801b84846132de565b905092915050565b606060035f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2080546123e290614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461240e90614e6a565b80156124595780601f1061243057610100808354040283529160200191612459565b820191905f5260205f20905b81548152906001019060200180831161243c57829003601f168201915b50505050509050919050565b5f805f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff16905060095f8267ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f015460095f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f20600101549250925050915091565b8261251181612b16565b612519575f80fd5b5f805f8681526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f60045f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f20805461258090614e6a565b80601f01602080910402602001604051908101604052809291908181526020018280546125ac90614e6a565b80156125f75780601f106125ce576101008083540402835291602001916125f7565b820191905f5260205f20905b8154815290600101906020018083116125da57829003601f168201915b50505050509050848460045f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f209182612641929190615220565b50857f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f8582878760405161267693929190615a99565b60405180910390a2505050505050565b8161269081612b16565b612698575f80fd5b6126c383603c846040516020016126af9190615b15565b60405160208183030381529060405261191a565b505050565b5f602052805f5260405f205f915054906101000a900467ffffffffffffffff1681565b60606126f88484846132de565b90509392505050565b8261270b81612b16565b612713575f80fd5b8160075f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847f7c69f06bea0bdef565b709e93a147836b0063ba2dd89f02d0b7e8d931e6a6daa846040516128459190614248565b60405180910390a350505050565b5f600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b60605f60025f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f209050805f8481526020019081526020015f20805461295890614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461298490614e6a565b80156129cf5780601f106129a6576101008083540402835291602001916129cf565b820191905f5260205f20905b8154815290600101906020018083116129b257829003601f168201915b505050505091505f82511480156129f357505f6129eb8461349f565b63ffffffff16115b15612a9657805f638000000081526020019081526020015f208054612a1790614e6a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a4390614e6a565b8015612a8e5780601f10612a6557610100808354040283529160200191612a8e565b820191905f5260205f20905b815481529060010190602001808311612a7157829003601f168201915b505050505091505b5092915050565b5f7f59d1d43c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612b0f5750612b0e826134d5565b5b9050919050565b5f81612b213361178d565b03612b2f5760019050612d10565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be3846040518263ffffffff1660e01b8152600401612b899190614635565b602060405180830381865afa158015612ba4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bc89190615b43565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612cba577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b8152600401612c789190615b6e565b602060405180830381865afa158015612c93573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cb79190615b43565b90505b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480612cfa5750612cf98133612853565b5b80612d0c5750612d0b8184336122c9565b5b9150505b919050565b612d1d613e93565b82815f0181905250818160c0018181525050612d3881613136565b92915050565b5f815f015151826020015110159050919050565b6060612d808260200151612d6d845f0151856020015161354e565b845f01516135c79092919063ffffffff16565b9050919050565b6060612db88260a001518360a001518460c00151612da59190614dba565b845f01516135c79092919063ffffffff16565b9050919050565b5f81518351148015612dde575081805190602001208380519060200120145b905092915050565b5f878051906020012090505f612e078686896135c79092919063ffffffff16565b90508315612f9c575f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f208054612e7590614e6a565b905014612ef85760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff1680929190612edc90615b87565b91906101000a81548161ffff021916908361ffff160217905550505b60055f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f8961ffff1661ffff1681526020019081526020015f205f612f5d9190613ed8565b897f03528ed0c2a3ebc993b12ce3c16bb382f9c7d88ef7d8a1bf290eaf35955a12078a8a604051612f8f929190615bbd565b60405180910390a261312a565b5f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f20805461300290614e6a565b9050036130855760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff168092919061306990615beb565b91906101000a81548161ffff021916908361ffff160217905550505b8060055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f2090816130ec919061548b565b50897f52a608b3303a48862d07a73d82fa221318c0027fbbcfb1b2329bface3f19ff2b8a8a8460405161312193929190615c14565b60405180910390a25b50505050505050505050565b8060c00151816020018181525050805f01515181602001511015613271575f613166825f0151836020015161354e565b82602001516131759190615c57565b905061318d81835f015161362c90919063ffffffff16565b826040019061ffff16908161ffff16815250506002816131ad9190615c57565b90506131c581835f015161362c90919063ffffffff16565b826060019061ffff16908161ffff16815250506002816131e59190615c57565b90506131fd81835f015161365590919063ffffffff16565b826080019063ffffffff16908163ffffffff16815250506004816132219190615c57565b90505f61323a82845f015161362c90919063ffffffff16565b61ffff16905060028261324d9190615c57565b9150818360a001818152505080826132659190615c57565b8360c001818152505050505b50565b5f638000000082148061329457505f61328c8361349f565b63ffffffff16115b9050919050565b5f80826028856132ab9190615c57565b146132bb575f80915091506132d6565b5f6132c786868661367e565b8093508192505050805f1c9250505b935093915050565b60608282905067ffffffffffffffff8111156132fd576132fc614652565b5b60405190808252806020026020018201604052801561333057816020015b606081526020019060019003908161331b5790505b5090505f5b83839050811015613497575f801b85146133d2575f84848381811061335d5761335c615191565b5b905060200281019061336f9190615c96565b60049060249261338193929190615562565b9061338c9190615cf8565b90508581146133d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133c790615dc6565b60405180910390fd5b505b5f803073ffffffffffffffffffffffffffffffffffffffff168686858181106133fe576133fd615191565b5b90506020028101906134109190615c96565b60405161341e929190615923565b5f60405180830381855af49150503d805f8114613456576040519150601f19603f3d011682016040523d82523d5f602084013e61345b565b606091505b509150915081613469575f80fd5b8084848151811061347d5761347c615191565b5b602002602001018190525050508080600101915050613335565b509392505050565b5f603c82036134b157600190506134d0565b638000000082189150638000000082106134cb575f6134cd565b815b90505b919050565b5f7fc8690233000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806135475750613546826136f9565b5b9050919050565b5f808290505b6001156135b2578351811061356c5761356b615de4565b5b5f613580828661377290919063ffffffff16565b60ff1690506001816135929190615c57565b8261359d9190615c57565b91505f81036135ac57506135b2565b50613554565b82816135be9190614dba565b91505092915050565b60608167ffffffffffffffff8111156135e3576135e2614652565b5b6040519080825280601f01601f1916602001820160405280156136155781602001600182028036833780820191505090505b5090506136258484835f866137b2565b9392505050565b5f6136438360028461363e9190615c57565b613802565b8160208401015160f01c905092915050565b5f61366c836004846136679190615c57565b613802565b8160208401015160e01c905092915050565b5f8083831015613693575f80915091506136f1565b5f84846136a09190614dba565b905060408111806136b15750855184115b156136c4575f801b5f92509250506136f1565b5f85602088010190506136d8815f8461384f565b92506001820160011c6020035f518160031b1c94505050505b935093915050565b5f7f691f3431000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061376b575061376a82613949565b5b9050919050565b5f613789836001846137849190615c57565b613802565b82828151811061379c5761379b615191565b5b602001015160f81c60f81b60f81c905092915050565b6137c78582866137c29190615c57565b613802565b6137dc8382846137d79190615c57565b613802565b6137fb826137e9856139c2565b01856137f4886139c2565b01836139ce565b5050505050565b815181111561384b578082516040517f8a3c1cfb000000000000000000000000000000000000000000000000000000008152600401613842929190615e11565b60405180910390fd5b5050565b5f6138b8565b5f81831a9150603a8210602f83111615613874576030820390506138b2565b6047821060408311161561389057600a604183030190506138b2565b606782106060831116156138ac57600a606183030190506138b2565b61010090505b92915050565b6001905081840160018316156138f4576138d35f8651613855565b80855360018601955060018501945060ff8111156138f2575f92508195505b505b5b8085101561394157845161390a600182613855565b6139145f83613855565b60041b1760ff81111561392b575f93505050613941565b80865350506002850194506001840193506138f5565b509392505050565b5f7f124a319c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806139bb57506139ba82613a1c565b5b9050919050565b5f602082019050919050565b5b601f8111156139f357815183526020830192506020820191506020810390506139cf565b8015613a17576001808260200360031b1b0380198351168185511680821786525050505b505050565b5f7fa8fa5682000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613ae657507f5c98042b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613af65750613af582613afd565b5b9050919050565b5f7fbc1c58d1000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613b6f5750613b6e82613b76565b5b9050919050565b5f817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f3b3b57de000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613c405750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167ff1cb7e06000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613ca85750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f32f111d7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613cb85750613cb782613cbf565b5b9050919050565b5f7f2203ab56000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613d315750613d3082613d38565b5b9050919050565b5f7fd700ff33000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613daa5750613da982613db1565b5b9050919050565b5f7f4fbf0433000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613e235750613e2282613e2a565b5b9050919050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6040518060e00160405280606081526020015f81526020015f61ffff1681526020015f61ffff1681526020015f63ffffffff1681526020015f81526020015f81525090565b508054613ee490614e6a565b5f825580601f10613ef55750613f12565b601f0160209004905f5260205f2090810190613f119190613f15565b5b50565b5b80821115613f2c575f815f905550600101613f16565b5090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613f7581613f41565b8114613f7f575f80fd5b50565b5f81359050613f9081613f6c565b92915050565b5f60208284031215613fab57613faa613f39565b5b5f613fb884828501613f82565b91505092915050565b5f8115159050919050565b613fd581613fc1565b82525050565b5f602082019050613fee5f830184613fcc565b92915050565b5f819050919050565b61400681613ff4565b8114614010575f80fd5b50565b5f8135905061402181613ffd565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261404857614047614027565b5b8235905067ffffffffffffffff8111156140655761406461402b565b5b6020830191508360018202830111156140815761408061402f565b5b9250929050565b5f805f6040848603121561409f5761409e613f39565b5b5f6140ac86828701614013565b935050602084013567ffffffffffffffff8111156140cd576140cc613f3d565b5b6140d986828701614033565b92509250509250925092565b5f8083601f8401126140fa576140f9614027565b5b8235905067ffffffffffffffff8111156141175761411661402b565b5b6020830191508360018202830111156141335761413261402f565b5b9250929050565b5f805f805f6060868803121561415357614152613f39565b5b5f61416088828901614013565b955050602086013567ffffffffffffffff81111561418157614180613f3d565b5b61418d888289016140e5565b9450945050604086013567ffffffffffffffff8111156141b0576141af613f3d565b5b6141bc888289016140e5565b92509250509295509295909350565b5f80604083850312156141e1576141e0613f39565b5b5f6141ee85828601614013565b92505060206141ff85828601613f82565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61423282614209565b9050919050565b61424281614228565b82525050565b5f60208201905061425b5f830184614239565b92915050565b5f819050919050565b61427381614261565b811461427d575f80fd5b50565b5f8135905061428e8161426a565b92915050565b5f80604083850312156142aa576142a9613f39565b5b5f6142b785828601614013565b92505060206142c885828601614280565b9150509250929050565b6142db81614261565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f614323826142e1565b61432d81856142eb565b935061433d8185602086016142fb565b61434681614309565b840191505092915050565b5f6040820190506143645f8301856142d2565b81810360208301526143768184614319565b90509392505050565b5f805f6060848603121561439657614395613f39565b5b5f6143a386828701614013565b93505060206143b486828701614013565b92505060406143c586828701614013565b9150509250925092565b5f602082840312156143e4576143e3613f39565b5b5f6143f184828501614013565b91505092915050565b5f61440482614209565b9050919050565b614414816143fa565b82525050565b5f60208201905061442d5f83018461440b565b92915050565b5f806040838503121561444957614448613f39565b5b5f61445685828601614013565b925050602061446785828601614013565b9150509250929050565b5f805f6040848603121561448857614487613f39565b5b5f61449586828701614013565b935050602084013567ffffffffffffffff8111156144b6576144b5613f3d565b5b6144c2868287016140e5565b92509250509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f6144f2826144ce565b6144fc81856144d8565b935061450c8185602086016142fb565b61451581614309565b840191505092915050565b5f6020820190508181035f83015261453881846144e8565b905092915050565b5f6020820190508181035f8301526145588184614319565b905092915050565b5f805f806060858703121561457857614577613f39565b5b5f61458587828801614013565b945050602061459687828801614280565b935050604085013567ffffffffffffffff8111156145b7576145b6613f3d565b5b6145c387828801614033565b925092505092959194509250565b6145da81614228565b81146145e4575f80fd5b50565b5f813590506145f5816145d1565b92915050565b5f602082840312156146105761460f613f39565b5b5f61461d848285016145e7565b91505092915050565b61462f81613ff4565b82525050565b5f6020820190506146485f830184614626565b92915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61468882614309565b810181811067ffffffffffffffff821117156146a7576146a6614652565b5b80604052505050565b5f6146b9613f30565b90506146c5828261467f565b919050565b5f67ffffffffffffffff8211156146e4576146e3614652565b5b6146ed82614309565b9050602081019050919050565b828183375f83830152505050565b5f61471a614715846146ca565b6146b0565b9050828152602081018484840111156147365761473561464e565b5b6147418482856146fa565b509392505050565b5f82601f83011261475d5761475c614027565b5b813561476d848260208601614708565b91505092915050565b5f805f6060848603121561478d5761478c613f39565b5b5f61479a86828701614013565b93505060206147ab86828701614280565b925050604084013567ffffffffffffffff8111156147cc576147cb613f3d565b5b6147d886828701614749565b9150509250925092565b5f805f80604085870312156147fa576147f9613f39565b5b5f85013567ffffffffffffffff81111561481757614816613f3d565b5b61482387828801614033565b9450945050602085013567ffffffffffffffff81111561484657614845613f3d565b5b61485287828801614033565b925092505092959194509250565b61486981613fc1565b8114614873575f80fd5b50565b5f8135905061488481614860565b92915050565b5f80604083850312156148a05761489f613f39565b5b5f6148ad858286016145e7565b92505060206148be85828601614876565b9150509250929050565b5f805f606084860312156148df576148de613f39565b5b5f6148ec86828701614013565b93505060206148fd868287016145e7565b925050604061490e86828701614876565b9150509250925092565b5f61ffff82169050919050565b61492e81614918565b8114614938575f80fd5b50565b5f8135905061494981614925565b92915050565b5f805f6060848603121561496657614965613f39565b5b5f61497386828701614013565b935050602061498486828701614013565b92505060406149958682870161493b565b9150509250925092565b5f805f606084860312156149b6576149b5613f39565b5b5f6149c3868287016145e7565b93505060206149d486828701614013565b92505060406149e5868287016145e7565b9150509250925092565b5f8083601f840112614a0457614a03614027565b5b8235905067ffffffffffffffff811115614a2157614a2061402b565b5b602083019150836020820283011115614a3d57614a3c61402f565b5b9250929050565b5f8060208385031215614a5a57614a59613f39565b5b5f83013567ffffffffffffffff811115614a7757614a76613f3d565b5b614a83858286016149ef565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f82825260208201905092915050565b5f614ad2826142e1565b614adc8185614ab8565b9350614aec8185602086016142fb565b614af581614309565b840191505092915050565b5f614b0b8383614ac8565b905092915050565b5f602082019050919050565b5f614b2982614a8f565b614b338185614a99565b935083602082028501614b4585614aa9565b805f5b85811015614b805784840389528151614b618582614b00565b9450614b6c83614b13565b925060208a01995050600181019050614b48565b50829750879550505050505092915050565b5f6020820190508181035f830152614baa8184614b1f565b905092915050565b5f604082019050614bc55f830185614626565b614bd26020830184614626565b9392505050565b5f8060408385031215614bef57614bee613f39565b5b5f614bfc85828601614013565b9250506020614c0d858286016145e7565b9150509250929050565b5f67ffffffffffffffff82169050919050565b614c3381614c17565b82525050565b5f602082019050614c4c5f830184614c2a565b92915050565b5f805f60408486031215614c6957614c68613f39565b5b5f614c7686828701614013565b935050602084013567ffffffffffffffff811115614c9757614c96613f3d565b5b614ca3868287016149ef565b92509250509250925092565b5f805f60608486031215614cc657614cc5613f39565b5b5f614cd386828701614013565b9350506020614ce486828701613f82565b9250506040614cf5868287016145e7565b9150509250925092565b5f8060408385031215614d1557614d14613f39565b5b5f614d22858286016145e7565b9250506020614d33858286016145e7565b9150509250929050565b5f81905092915050565b5f614d51826142e1565b614d5b8185614d3d565b9350614d6b8185602086016142fb565b80840191505092915050565b5f614d828284614d47565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614dc482614261565b9150614dcf83614261565b9250828203905081811115614de757614de6614d8d565b5b92915050565b5f81905092915050565b5f614e028385614ded565b9350614e0f8385846146fa565b82840190509392505050565b5f614e27828486614df7565b91508190509392505050565b5f82905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680614e8157607f821691505b602082108103614e9457614e93614e3d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302614ef67fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614ebb565b614f008683614ebb565b95508019841693508086168417925050509392505050565b5f819050919050565b5f614f3b614f36614f3184614261565b614f18565b614261565b9050919050565b5f819050919050565b614f5483614f21565b614f68614f6082614f42565b848454614ec7565b825550505050565b5f90565b614f7c614f70565b614f87818484614f4b565b505050565b5b81811015614faa57614f9f5f82614f74565b600181019050614f8d565b5050565b601f821115614fef57614fc081614e9a565b614fc984614eac565b81016020851015614fd8578190505b614fec614fe485614eac565b830182614f8c565b50505b505050565b5f82821c905092915050565b5f61500f5f1984600802614ff4565b1980831691505092915050565b5f6150278383615000565b9150826002028217905092915050565b6150418383614e33565b67ffffffffffffffff81111561505a57615059614652565b5b6150648254614e6a565b61506f828285614fae565b5f601f83116001811461509c575f841561508a578287013590505b615094858261501c565b8655506150fb565b601f1984166150aa86614e9a565b5f5b828110156150d1578489013582556001820191506020850194506020810190506150ac565b868310156150ee57848901356150ea601f891682615000565b8355505b6001600288020188555050505b50505050505050565b5f61510f83856144d8565b935061511c8385846146fa565b61512583614309565b840190509392505050565b5f6040820190508181035f830152615149818688615104565b9050818103602083015261515e818486615104565b905095945050505050565b61517281613f41565b82525050565b5f60208201905061518b5f830184615169565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82905092915050565b5f819050815f5260205f209050919050565b601f82111561521b576151ec816151c8565b6151f584614eac565b81016020851015615204578190505b61521861521085614eac565b830182614f8c565b50505b505050565b61522a83836151be565b67ffffffffffffffff81111561524357615242614652565b5b61524d8254614e6a565b6152588282856151da565b5f601f831160018114615285575f8415615273578287013590505b61527d858261501c565b8655506152e4565b601f198416615293866151c8565b5f5b828110156152ba57848901358255600182019150602085019450602081019050615295565b868310156152d757848901356152d3601f891682615000565b8355505b6001600288020188555050505b50505050505050565b5f6152f883856142eb565b93506153058385846146fa565b61530e83614309565b840190509392505050565b5f6020820190508181035f8301526153328184866152ed565b90509392505050565b5f61534582614c17565b915067ffffffffffffffff820361535f5761535e614d8d565b5b600182019050919050565b5f819050602082019050919050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f6153af8251615379565b80915050919050565b5f6153c2826142e1565b826153cc8461536a565b90506153d7816153a4565b92506014821015615417576154127fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802614ebb565b831692505b5050919050565b5f819050919050565b61543861543382613ff4565b61541e565b82525050565b5f6154498285615427565b6020820191506154598284615427565b6020820191508190509392505050565b5f6020820190508181035f830152615482818486615104565b90509392505050565b615494826142e1565b67ffffffffffffffff8111156154ad576154ac614652565b5b6154b78254614e6a565b6154c28282856151da565b5f60209050601f8311600181146154f3575f84156154e1578287015190505b6154eb858261501c565b865550615552565b601f198416615501866151c8565b5f5b8281101561552857848901518255600182019150602085019450602081019050615503565b868310156155455784890151615541601f891682615000565b8355505b6001600288020188555050505b505050505050565b5f80fd5b5f80fd5b5f80858511156155755761557461555a565b5b838611156155865761558561555e565b5b6001850283019150848603905094509492505050565b7f496e76616c6964206865782061646472657373000000000000000000000000005f82015250565b5f6155d06013836144d8565b91506155db8261559c565b602082019050919050565b5f6020820190508181035f8301526155fd816155c4565b9050919050565b5f61560f83836151be565b8261561a8135613f41565b9250600482101561565a576156557fffffffff0000000000000000000000000000000000000000000000000000000083600403600802614ebb565b831692505b505092915050565b5f67ffffffffffffffff82111561567c5761567b614652565b5b61568582614309565b9050602081019050919050565b5f6156a461569f84615662565b6146b0565b9050828152602081018484840111156156c0576156bf61464e565b5b6156cb8482856146fa565b509392505050565b5f82601f8301126156e7576156e6614027565b5b81356156f7848260208601615692565b91505092915050565b5f806040838503121561571657615715613f39565b5b5f61572385828601614013565b925050602083013567ffffffffffffffff81111561574457615743613f3d565b5b615750858286016156d3565b9150509250929050565b5f60408201905061576d5f830185614626565b818103602083015261577f81846144e8565b90509392505050565b5f61579a61579584615662565b6146b0565b9050828152602081018484840111156157b6576157b561464e565b5b6157c18482856142fb565b509392505050565b5f82601f8301126157dd576157dc614027565b5b81516157ed848260208601615788565b91505092915050565b5f6020828403121561580b5761580a613f39565b5b5f82015167ffffffffffffffff81111561582857615827613f3d565b5b615834848285016157c9565b91505092915050565b5f819050919050565b61585761585282613f41565b61583d565b82525050565b5f6158688385614d3d565b93506158758385846146fa565b82840190509392505050565b5f61588c8287615846565b60048201915061589c8286615427565b6020820191506158ad82848661585d565b915081905095945050505050565b7f556e737570706f727465642066756e6374696f6e0000000000000000000000005f82015250565b5f6158ef6014836144d8565b91506158fa826158bb565b602082019050919050565b5f6020820190508181035f83015261591c816158e3565b9050919050565b5f61592f82848661585d565b91508190509392505050565b7f5265736f6c7574696f6e206661696c65640000000000000000000000000000005f82015250565b5f61596f6011836144d8565b915061597a8261593b565b602082019050919050565b5f6020820190508181035f83015261599c81615963565b9050919050565b7f455243313135353a2073657474696e6720617070726f76616c207374617475735f8201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b5f6159fd6029836144d8565b9150615a08826159a3565b604082019050919050565b5f6020820190508181035f830152615a2a816159f1565b9050919050565b7f53657474696e672064656c65676174652073746174757320666f722073656c665f82015250565b5f615a656020836144d8565b9150615a7082615a31565b602082019050919050565b5f6020820190508181035f830152615a9281615a59565b9050919050565b5f6040820190508181035f830152615ab18186614319565b90508181036020830152615ac68184866152ed565b9050949350505050565b5f8160601b9050919050565b5f615ae682615ad0565b9050919050565b5f615af782615adc565b9050919050565b615b0f615b0a82614228565b615aed565b82525050565b5f615b208284615afe565b60148201915081905092915050565b5f81519050615b3d816145d1565b92915050565b5f60208284031215615b5857615b57613f39565b5b5f615b6584828501615b2f565b91505092915050565b5f602082019050615b815f8301846142d2565b92915050565b5f615b9182614918565b91505f8203615ba357615ba2614d8d565b5b600182039050919050565b615bb781614918565b82525050565b5f6040820190508181035f830152615bd58185614319565b9050615be46020830184615bae565b9392505050565b5f615bf582614918565b915061ffff8203615c0957615c08614d8d565b5b600182019050919050565b5f6060820190508181035f830152615c2c8186614319565b9050615c3b6020830185615bae565b8181036040830152615c4d8184614319565b9050949350505050565b5f615c6182614261565b9150615c6c83614261565b9250828201905080821115615c8457615c83614d8d565b5b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083356001602003843603038112615cb257615cb1615c8a565b5b80840192508235915067ffffffffffffffff821115615cd457615cd3615c8e565b5b602083019250600182023603831315615cf057615cef615c92565b5b509250929050565b5f615d0383836151be565b82615d0e8135613ff4565b92506020821015615d4e57615d497fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802614ebb565b831692505b505092915050565b7f6d756c746963616c6c3a20416c6c207265636f726473206d75737420686176655f8201527f2061206d61746368696e67206e616d6568617368000000000000000000000000602082015250565b5f615db06034836144d8565b9150615dbb82615d56565b604082019050919050565b5f6020820190508181035f830152615ddd81615da4565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b5f604082019050615e245f8301856142d2565b615e3160208301846142d2565b939250505056fea2646970667358221220666f59a975a4c8228cbda082edea45bee7ea37187b083599527ba9c97134fb6f64736f6c6343000819003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "nonce": "0x3",
+ "chainId": "0x14a34"
+ },
+ "additionalContracts": [],
+ "isFixedGasLimit": false
+ }
+ ],
+ "receipts": [
+ {
+ "status": "0x1",
+ "cumulativeGasUsed": "0x90dd05",
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "type": "0x2",
+ "transactionHash": "0x5349252e11494c3eb04faefde3b94b6a7e8abb41a89af880771ff6ac3bf7882d",
+ "transactionIndex": "0x9",
+ "blockHash": "0x168e9322c12cfb1991ad6c6208ba4be7c06f656991aecd33fec9084b493ad1be",
+ "blockNumber": "0x21c3e15",
+ "gasUsed": "0x507d93",
+ "effectiveGasPrice": "0xe0f3b8",
+ "blobGasUsed": "0x321408",
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "to": null,
+ "contractAddress": "0xa66c55a6b76967477af18a03f2f12d52251dc2c0",
+ "daFootprintGasScalar": "0x138",
+ "l1BaseFeeScalar": "0x44d",
+ "l1BlobBaseFee": "0x39aec6f64",
+ "l1BlobBaseFeeScalar": "0xa118b",
+ "l1Fee": "0x61c42bfc559d",
+ "l1GasPrice": "0x3a6b8fd",
+ "l1GasUsed": "0x2917e"
+ }
+ ],
+ "libraries": [],
+ "pending": [],
+ "returns": {
+ "resolver": {
+ "internal_type": "contract ConfigResolver",
+ "value": "0xA66c55a6b76967477af18A03F2f12d52251Dc2C0"
+ }
+ },
+ "timestamp": 1766578976219,
+ "chain": 84532,
+ "commit": "c437ed7"
+}
\ No newline at end of file
diff --git a/broadcast/Deploy.s.sol/84532/run-1766578976219.json b/broadcast/Deploy.s.sol/84532/run-1766578976219.json
new file mode 100644
index 0000000..a69a2af
--- /dev/null
+++ b/broadcast/Deploy.s.sol/84532/run-1766578976219.json
@@ -0,0 +1,62 @@
+{
+ "transactions": [
+ {
+ "hash": "0x5349252e11494c3eb04faefde3b94b6a7e8abb41a89af880771ff6ac3bf7882d",
+ "transactionType": "CREATE",
+ "contractName": "ConfigResolver",
+ "contractAddress": "0xa66c55a6b76967477af18a03f2f12d52251dc2c0",
+ "function": null,
+ "arguments": [
+ "0x0000000000000000000000000000000000000000",
+ "0x0000000000000000000000000000000000000000"
+ ],
+ "transaction": {
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "gas": "0x68a33f",
+ "value": "0x0",
+ "input": "0x60c060405234801561000f575f80fd5b5060405161601e38038061601e8339818101604052810190610031919061014a565b8173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250505050610188565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100cd826100a4565b9050919050565b5f6100de826100c3565b9050919050565b6100ee816100d4565b81146100f8575f80fd5b50565b5f81519050610109816100e5565b92915050565b5f610119826100c3565b9050919050565b6101298161010f565b8114610133575f80fd5b50565b5f8151905061014481610120565b92915050565b5f80604083850312156101605761015f6100a0565b5b5f61016d858286016100fb565b925050602061017e85828601610136565b9150509250929050565b60805160a051615e6e6101b05f395f8181612bcc0152612c1f01525f612b320152615e6e5ff3fe608060405234801561000f575f80fd5b50600436106101f9575f3560e01c80637737221311610118578063bc1c58d1116100ab578063d700ff331161007a578063d700ff331461064f578063e32954eb1461067f578063e59d895d146106af578063e985e9c5146106cb578063f1cb7e06146106fb576101f9565b8063bc1c58d1146105b6578063c8690233146105e6578063ce3decdc14610617578063d5fa2b0014610633576101f9565b8063a4b91a01116100e7578063a4b91a011461050a578063a8fa568214610526578063a9784b3e14610556578063ac9650d814610586576101f9565b806377372213146104865780638b95dd71146104a25780639061b923146104be578063a22cb465146104ee576101f9565b80633603d758116101905780635c98042b1161015f5780635c98042b146103da578063623195b01461040a578063691f3431146104265780637315937d14610456576101f9565b80633603d7581461032e5780633b3b57de1461034a5780634cbf6ba41461037a57806359d1d43c146103aa576101f9565b80632203ab56116101cc5780632203ab561461029557806329cd62ea146102c6578063304e6ade146102e257806332f111d7146102fe576101f9565b806301ffc9a7146101fd5780630af179d71461022d57806310f13a8c14610249578063124a319c14610265575b5f80fd5b61021760048036038101906102129190613f96565b61072b565b6040516102249190613fdb565b60405180910390f35b61024760048036038101906102429190614088565b61076c565b005b610263600480360381019061025e919061413a565b6109bb565b005b61027f600480360381019061027a91906141cb565b610ab0565b60405161028c9190614248565b60405180910390f35b6102af60048036038101906102aa9190614294565b610ef1565b6040516102bd929190614351565b60405180910390f35b6102e060048036038101906102db919061437f565b61106a565b005b6102fc60048036038101906102f79190614088565b61113d565b005b61031860048036038101906103139190614294565b6111f6565b6040516103259190613fdb565b60405180910390f35b610348600480360381019061034391906143cf565b611274565b005b610364600480360381019061035f91906143cf565b61133f565b604051610371919061441a565b60405180910390f35b610394600480360381019061038f9190614433565b61135e565b6040516103a19190613fdb565b60405180910390f35b6103c460048036038101906103bf9190614471565b6113e2565b6040516103d19190614520565b60405180910390f35b6103f460048036038101906103ef91906143cf565b6114e9565b6040516104019190614540565b60405180910390f35b610424600480360381019061041f9190614560565b6115d0565b005b610440600480360381019061043b91906143cf565b6116a6565b60405161044d9190614520565b60405180910390f35b610470600480360381019061046b91906145fb565b61178d565b60405161047d9190614635565b60405180910390f35b6104a0600480360381019061049b9190614471565b611861565b005b6104bc60048036038101906104b79190614776565b61191a565b005b6104d860048036038101906104d391906147e2565b611a93565b6040516104e59190614540565b60405180910390f35b6105086004803603810190610503919061488a565b611ef1565b005b610524600480360381019061051f91906148c8565b612057565b005b610540600480360381019061053b919061494f565b6121ba565b60405161054d9190614540565b60405180910390f35b610570600480360381019061056b919061499f565b6122c9565b60405161057d9190613fdb565b60405180910390f35b6105a0600480360381019061059b9190614a44565b612367565b6040516105ad9190614b92565b60405180910390f35b6105d060048036038101906105cb91906143cf565b61237e565b6040516105dd9190614540565b60405180910390f35b61060060048036038101906105fb91906143cf565b612465565b60405161060e929190614bb2565b60405180910390f35b610631600480360381019061062c9190614088565b612507565b005b61064d60048036038101906106489190614bd9565b612686565b005b610669600480360381019061066491906143cf565b6126c8565b6040516106769190614c39565b60405180910390f35b61069960048036038101906106949190614c52565b6126eb565b6040516106a69190614b92565b60405180910390f35b6106c960048036038101906106c49190614caf565b612701565b005b6106e560048036038101906106e09190614cff565b612853565b6040516106f29190613fdb565b60405180910390f35b61071560048036038101906107109190614294565b6128e1565b6040516107229190614540565b60405180910390f35b5f639061b92360e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610765575061076482612a9d565b5b9050919050565b8261077681612b16565b61077e575f80fd5b5f806060805f805f808b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f6108025f8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612d1590919063ffffffff16565b90505b61080e81612d3e565b610940575f8761ffff1603610868578060400151965061082d81612d52565b9450846040516020016108409190614d77565b60405160208183030381529060405280519060200120925061086181612d87565b9350610932565b5f61087282612d52565b9050816040015161ffff168861ffff1614158061089f575061089d8187612dbf90919063ffffffff16565b155b15610930576109098c878a8e8e8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050508b8c88602001516108ff9190614dba565b5f8c51148a612de6565b81604001519750816020015196508095508580519060200120935061092d82612d87565b94505b505b61093b81613136565b610805565b505f845111156109af576109ae8a85888c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050898a8f8f90506109a49190614dba565b5f8a511488612de6565b5b50505050505050505050565b846109c581612b16565b6109cd575f80fd5b8282600a5f805f8b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f208787604051610a36929190614e1b565b90815260200160405180910390209182610a51929190615037565b508484604051610a62929190614e1b565b6040518091039020867f448bc014f1536726cf8d54ff3d6481ed3cbc683c2591ca204274009afa09b1a187878787604051610aa09493929190615130565b60405180910390a3505050505050565b5f8060075f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610bb45780915050610eeb565b5f610bbe8561133f565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610bfd575f92505050610eeb565b5f808273ffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000604051602401610c479190615178565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610cd19190614d77565b5f60405180830381855afa9150503d805f8114610d09576040519150601f19603f3d011682016040523d82523d5f602084013e610d0e565b606091505b5091509150811580610d21575060208151105b80610d6e57505f60f81b81601f81518110610d3f57610d3e615191565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610d7f575f945050505050610eeb565b8273ffffffffffffffffffffffffffffffffffffffff1686604051602401610da79190615178565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610e319190614d77565b5f60405180830381855afa9150503d805f8114610e69576040519150601f19603f3d011682016040523d82523d5f602084013e610e6e565b606091505b508092508193505050811580610e85575060208151105b80610ed257505f60f81b81601f81518110610ea357610ea2615191565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610ee3575f945050505050610eeb565b829450505050505b92915050565b5f60605f60015f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f2090505f600190505b5f81118015610f635750848111155b1561104c575f85821614158015610f9557505f825f8381526020019081526020015f208054610f9190614e6a565b9050115b156110405780825f8381526020019081526020015f20808054610fb790614e6a565b80601f0160208091040260200160405190810160405280929190818152602001828054610fe390614e6a565b801561102e5780601f106110055761010080835404028352916020019161102e565b820191905f5260205f20905b81548152906001019060200180831161101157829003601f168201915b50505050509050935093505050611063565b600181901b9050610f54565b505f60405180602001604052805f81525092509250505b9250929050565b8261107481612b16565b61107c575f80fd5b60405180604001604052808481526020018381525060095f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f820151815f015560208201518160010155905050837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e46848460405161112f929190614bb2565b60405180910390a250505050565b8261114781612b16565b61114f575f80fd5b828260035f805f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f2091826111b5929190615220565b50837fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d757884846040516111e8929190615319565b60405180910390a250505050565b5f8060025f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f20805461126990614e6a565b905011905092915050565b8061127e81612b16565b611286575f80fd5b5f808381526020019081526020015f205f81819054906101000a900467ffffffffffffffff16809291906112b99061533b565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050817fc6621ccb8f3f5a04bb6502154b2caf6adf5983fe76dfef1cfc9c42e3579db4445f808581526020019081526020015f205f9054906101000a900467ffffffffffffffff166040516113339190614c39565b60405180910390a25050565b5f61134b82603c6128e1565b611354906153b8565b60601c9050919050565b5f8060065f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f9054906101000a900461ffff1661ffff161415905092915050565b6060600a5f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f20838360405161144b929190614e1b565b9081526020016040518091039020805461146490614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461149090614e6a565b80156114db5780601f106114b2576101008083540402835291602001916114db565b820191905f5260205f20905b8154815290600101906020018083116114be57829003601f168201915b505050505090509392505050565b606060045f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f20805461154d90614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461157990614e6a565b80156115c45780601f1061159b576101008083540402835291602001916115c4565b820191905f5260205f20905b8154815290600101906020018083116115a757829003601f168201915b50505050509050919050565b836115da81612b16565b6115e2575f80fd5b5f846001866115f19190614dba565b16146115fb575f80fd5b828260015f805f8a81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8881526020019081526020015f205f8781526020019081526020015f209182611670929190615220565b5083857faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a35050505050565b606060085f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f20805461170a90614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461173690614e6a565b80156117815780601f1061175857610100808354040283529160200191611781565b820191905f5260205f20905b81548152906001019060200180831161176457829003601f168201915b50505050509050919050565b5f8060285b5f811115611807576001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a81536010840493506001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a8153601084049350611792565b5060285f2090507f91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e25f1b8160405160200161184392919061543e565b60405160208183030381529060405280519060200120915050919050565b8261186b81612b16565b611873575f80fd5b828260085f805f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f2091826118d9929190615037565b50837fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f7848460405161190c929190615469565b60405180910390a250505050565b8261192481612b16565b61192c575f80fd5b5f82511415801561193f57506014825114155b8015611950575061194f83613274565b5b1561199257816040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016119899190614540565b60405180910390fd5b837f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af75284846040516119c4929190614351565b60405180910390a2603c8303611a1957837f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd283611a00906153b8565b60601c604051611a109190614248565b60405180910390a25b8160025f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f8581526020019081526020015f209081611a8c919061548b565b5050505050565b60605f85855f818110611aa957611aa8615191565b5b9050013560f81c60f81b60f81c60ff16905060288103611e32575f8686600190602992611ad893929190615562565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505090505f80611b345f60288561329b9092919063ffffffff16565b9150915080611b78576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b6f906155e6565b60405180910390fd5b5f611b828361178d565b90505f88885f90600492611b9893929190615562565b90611ba39190615604565b9050633b3b57de60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611c1e5783604051602001611c029190614248565b6040516020818303038152906040529650505050505050611ee9565b6359d1d43c60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191603611d3d575f89896004908092611c7e93929190615562565b810190611c8b9190615700565b9150505f3073ffffffffffffffffffffffffffffffffffffffff166359d1d43c85846040518363ffffffff1660e01b8152600401611cca92919061575a565b5f60405180830381865afa158015611ce4573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611d0c91906157f6565b905080604051602001611d1f9190614520565b60405160208183030381529060405298505050505050505050611ee9565b5f81838b8b6024908092611d5393929190615562565b604051602001611d669493929190615881565b60405160208183030381529060405290505f803073ffffffffffffffffffffffffffffffffffffffff1683604051611d9e9190614d77565b5f60405180830381855afa9150503d805f8114611dd6576040519150601f19603f3d011682016040523d82523d5f602084013e611ddb565b606091505b50915091508115611df757809950505050505050505050611ee9565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e2990615905565b60405180910390fd5b5f803073ffffffffffffffffffffffffffffffffffffffff168686604051611e5b929190615923565b5f60405180830381855afa9150503d805f8114611e93576040519150601f19603f3d011682016040523d82523d5f602084013e611e98565b606091505b50915091508115611eae57809350505050611ee9565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee090615985565b60405180910390fd5b949350505050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603611f5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f5690615a13565b60405180910390fd5b80600b5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405161204b9190613fdb565b60405180910390a35050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16036120c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120bc90615a7b565b60405180910390fd5b80600c5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508015158273ffffffffffffffffffffffffffffffffffffffff16847ff0ddb3b04746704017f9aa8bd728fcc2c1d11675041205350018915f5e4750a0336040516121ad9190614248565b60405180910390a4505050565b606060055f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f8361ffff1661ffff1681526020019081526020015f20805461224490614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461227090614e6a565b80156122bb5780601f10612292576101008083540402835291602001916122bb565b820191905f5260205f20905b81548152906001019060200180831161229e57829003601f168201915b505050505090509392505050565b5f600c5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1690509392505050565b60606123765f801b84846132de565b905092915050565b606060035f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2080546123e290614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461240e90614e6a565b80156124595780601f1061243057610100808354040283529160200191612459565b820191905f5260205f20905b81548152906001019060200180831161243c57829003601f168201915b50505050509050919050565b5f805f805f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff16905060095f8267ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f015460095f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f20600101549250925050915091565b8261251181612b16565b612519575f80fd5b5f805f8681526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f60045f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f20805461258090614e6a565b80601f01602080910402602001604051908101604052809291908181526020018280546125ac90614e6a565b80156125f75780601f106125ce576101008083540402835291602001916125f7565b820191905f5260205f20905b8154815290600101906020018083116125da57829003601f168201915b50505050509050848460045f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f209182612641929190615220565b50857f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f8582878760405161267693929190615a99565b60405180910390a2505050505050565b8161269081612b16565b612698575f80fd5b6126c383603c846040516020016126af9190615b15565b60405160208183030381529060405261191a565b505050565b5f602052805f5260405f205f915054906101000a900467ffffffffffffffff1681565b60606126f88484846132de565b90509392505050565b8261270b81612b16565b612713575f80fd5b8160075f805f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847f7c69f06bea0bdef565b709e93a147836b0063ba2dd89f02d0b7e8d931e6a6daa846040516128459190614248565b60405180910390a350505050565b5f600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b60605f60025f805f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f209050805f8481526020019081526020015f20805461295890614e6a565b80601f016020809104026020016040519081016040528092919081815260200182805461298490614e6a565b80156129cf5780601f106129a6576101008083540402835291602001916129cf565b820191905f5260205f20905b8154815290600101906020018083116129b257829003601f168201915b505050505091505f82511480156129f357505f6129eb8461349f565b63ffffffff16115b15612a9657805f638000000081526020019081526020015f208054612a1790614e6a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a4390614e6a565b8015612a8e5780601f10612a6557610100808354040283529160200191612a8e565b820191905f5260205f20905b815481529060010190602001808311612a7157829003601f168201915b505050505091505b5092915050565b5f7f59d1d43c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480612b0f5750612b0e826134d5565b5b9050919050565b5f81612b213361178d565b03612b2f5760019050612d10565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be3846040518263ffffffff1660e01b8152600401612b899190614635565b602060405180830381865afa158015612ba4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bc89190615b43565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612cba577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b8152600401612c789190615b6e565b602060405180830381865afa158015612c93573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cb79190615b43565b90505b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480612cfa5750612cf98133612853565b5b80612d0c5750612d0b8184336122c9565b5b9150505b919050565b612d1d613e93565b82815f0181905250818160c0018181525050612d3881613136565b92915050565b5f815f015151826020015110159050919050565b6060612d808260200151612d6d845f0151856020015161354e565b845f01516135c79092919063ffffffff16565b9050919050565b6060612db88260a001518360a001518460c00151612da59190614dba565b845f01516135c79092919063ffffffff16565b9050919050565b5f81518351148015612dde575081805190602001208380519060200120145b905092915050565b5f878051906020012090505f612e078686896135c79092919063ffffffff16565b90508315612f9c575f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f208054612e7590614e6a565b905014612ef85760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff1680929190612edc90615b87565b91906101000a81548161ffff021916908361ffff160217905550505b60055f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f8961ffff1661ffff1681526020019081526020015f205f612f5d9190613ed8565b897f03528ed0c2a3ebc993b12ce3c16bb382f9c7d88ef7d8a1bf290eaf35955a12078a8a604051612f8f929190615bbd565b60405180910390a261312a565b5f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f20805461300290614e6a565b9050036130855760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff168092919061306990615beb565b91906101000a81548161ffff021916908361ffff160217905550505b8060055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f2090816130ec919061548b565b50897f52a608b3303a48862d07a73d82fa221318c0027fbbcfb1b2329bface3f19ff2b8a8a8460405161312193929190615c14565b60405180910390a25b50505050505050505050565b8060c00151816020018181525050805f01515181602001511015613271575f613166825f0151836020015161354e565b82602001516131759190615c57565b905061318d81835f015161362c90919063ffffffff16565b826040019061ffff16908161ffff16815250506002816131ad9190615c57565b90506131c581835f015161362c90919063ffffffff16565b826060019061ffff16908161ffff16815250506002816131e59190615c57565b90506131fd81835f015161365590919063ffffffff16565b826080019063ffffffff16908163ffffffff16815250506004816132219190615c57565b90505f61323a82845f015161362c90919063ffffffff16565b61ffff16905060028261324d9190615c57565b9150818360a001818152505080826132659190615c57565b8360c001818152505050505b50565b5f638000000082148061329457505f61328c8361349f565b63ffffffff16115b9050919050565b5f80826028856132ab9190615c57565b146132bb575f80915091506132d6565b5f6132c786868661367e565b8093508192505050805f1c9250505b935093915050565b60608282905067ffffffffffffffff8111156132fd576132fc614652565b5b60405190808252806020026020018201604052801561333057816020015b606081526020019060019003908161331b5790505b5090505f5b83839050811015613497575f801b85146133d2575f84848381811061335d5761335c615191565b5b905060200281019061336f9190615c96565b60049060249261338193929190615562565b9061338c9190615cf8565b90508581146133d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133c790615dc6565b60405180910390fd5b505b5f803073ffffffffffffffffffffffffffffffffffffffff168686858181106133fe576133fd615191565b5b90506020028101906134109190615c96565b60405161341e929190615923565b5f60405180830381855af49150503d805f8114613456576040519150601f19603f3d011682016040523d82523d5f602084013e61345b565b606091505b509150915081613469575f80fd5b8084848151811061347d5761347c615191565b5b602002602001018190525050508080600101915050613335565b509392505050565b5f603c82036134b157600190506134d0565b638000000082189150638000000082106134cb575f6134cd565b815b90505b919050565b5f7fc8690233000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806135475750613546826136f9565b5b9050919050565b5f808290505b6001156135b2578351811061356c5761356b615de4565b5b5f613580828661377290919063ffffffff16565b60ff1690506001816135929190615c57565b8261359d9190615c57565b91505f81036135ac57506135b2565b50613554565b82816135be9190614dba565b91505092915050565b60608167ffffffffffffffff8111156135e3576135e2614652565b5b6040519080825280601f01601f1916602001820160405280156136155781602001600182028036833780820191505090505b5090506136258484835f866137b2565b9392505050565b5f6136438360028461363e9190615c57565b613802565b8160208401015160f01c905092915050565b5f61366c836004846136679190615c57565b613802565b8160208401015160e01c905092915050565b5f8083831015613693575f80915091506136f1565b5f84846136a09190614dba565b905060408111806136b15750855184115b156136c4575f801b5f92509250506136f1565b5f85602088010190506136d8815f8461384f565b92506001820160011c6020035f518160031b1c94505050505b935093915050565b5f7f691f3431000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061376b575061376a82613949565b5b9050919050565b5f613789836001846137849190615c57565b613802565b82828151811061379c5761379b615191565b5b602001015160f81c60f81b60f81c905092915050565b6137c78582866137c29190615c57565b613802565b6137dc8382846137d79190615c57565b613802565b6137fb826137e9856139c2565b01856137f4886139c2565b01836139ce565b5050505050565b815181111561384b578082516040517f8a3c1cfb000000000000000000000000000000000000000000000000000000008152600401613842929190615e11565b60405180910390fd5b5050565b5f6138b8565b5f81831a9150603a8210602f83111615613874576030820390506138b2565b6047821060408311161561389057600a604183030190506138b2565b606782106060831116156138ac57600a606183030190506138b2565b61010090505b92915050565b6001905081840160018316156138f4576138d35f8651613855565b80855360018601955060018501945060ff8111156138f2575f92508195505b505b5b8085101561394157845161390a600182613855565b6139145f83613855565b60041b1760ff81111561392b575f93505050613941565b80865350506002850194506001840193506138f5565b509392505050565b5f7f124a319c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806139bb57506139ba82613a1c565b5b9050919050565b5f602082019050919050565b5b601f8111156139f357815183526020830192506020820191506020810390506139cf565b8015613a17576001808260200360031b1b0380198351168185511680821786525050505b505050565b5f7fa8fa5682000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613ae657507f5c98042b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613af65750613af582613afd565b5b9050919050565b5f7fbc1c58d1000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613b6f5750613b6e82613b76565b5b9050919050565b5f817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f3b3b57de000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613c405750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167ff1cb7e06000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613ca85750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f32f111d7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613cb85750613cb782613cbf565b5b9050919050565b5f7f2203ab56000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613d315750613d3082613d38565b5b9050919050565b5f7fd700ff33000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613daa5750613da982613db1565b5b9050919050565b5f7f4fbf0433000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613e235750613e2282613e2a565b5b9050919050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6040518060e00160405280606081526020015f81526020015f61ffff1681526020015f61ffff1681526020015f63ffffffff1681526020015f81526020015f81525090565b508054613ee490614e6a565b5f825580601f10613ef55750613f12565b601f0160209004905f5260205f2090810190613f119190613f15565b5b50565b5b80821115613f2c575f815f905550600101613f16565b5090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b613f7581613f41565b8114613f7f575f80fd5b50565b5f81359050613f9081613f6c565b92915050565b5f60208284031215613fab57613faa613f39565b5b5f613fb884828501613f82565b91505092915050565b5f8115159050919050565b613fd581613fc1565b82525050565b5f602082019050613fee5f830184613fcc565b92915050565b5f819050919050565b61400681613ff4565b8114614010575f80fd5b50565b5f8135905061402181613ffd565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261404857614047614027565b5b8235905067ffffffffffffffff8111156140655761406461402b565b5b6020830191508360018202830111156140815761408061402f565b5b9250929050565b5f805f6040848603121561409f5761409e613f39565b5b5f6140ac86828701614013565b935050602084013567ffffffffffffffff8111156140cd576140cc613f3d565b5b6140d986828701614033565b92509250509250925092565b5f8083601f8401126140fa576140f9614027565b5b8235905067ffffffffffffffff8111156141175761411661402b565b5b6020830191508360018202830111156141335761413261402f565b5b9250929050565b5f805f805f6060868803121561415357614152613f39565b5b5f61416088828901614013565b955050602086013567ffffffffffffffff81111561418157614180613f3d565b5b61418d888289016140e5565b9450945050604086013567ffffffffffffffff8111156141b0576141af613f3d565b5b6141bc888289016140e5565b92509250509295509295909350565b5f80604083850312156141e1576141e0613f39565b5b5f6141ee85828601614013565b92505060206141ff85828601613f82565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61423282614209565b9050919050565b61424281614228565b82525050565b5f60208201905061425b5f830184614239565b92915050565b5f819050919050565b61427381614261565b811461427d575f80fd5b50565b5f8135905061428e8161426a565b92915050565b5f80604083850312156142aa576142a9613f39565b5b5f6142b785828601614013565b92505060206142c885828601614280565b9150509250929050565b6142db81614261565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f614323826142e1565b61432d81856142eb565b935061433d8185602086016142fb565b61434681614309565b840191505092915050565b5f6040820190506143645f8301856142d2565b81810360208301526143768184614319565b90509392505050565b5f805f6060848603121561439657614395613f39565b5b5f6143a386828701614013565b93505060206143b486828701614013565b92505060406143c586828701614013565b9150509250925092565b5f602082840312156143e4576143e3613f39565b5b5f6143f184828501614013565b91505092915050565b5f61440482614209565b9050919050565b614414816143fa565b82525050565b5f60208201905061442d5f83018461440b565b92915050565b5f806040838503121561444957614448613f39565b5b5f61445685828601614013565b925050602061446785828601614013565b9150509250929050565b5f805f6040848603121561448857614487613f39565b5b5f61449586828701614013565b935050602084013567ffffffffffffffff8111156144b6576144b5613f3d565b5b6144c2868287016140e5565b92509250509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f6144f2826144ce565b6144fc81856144d8565b935061450c8185602086016142fb565b61451581614309565b840191505092915050565b5f6020820190508181035f83015261453881846144e8565b905092915050565b5f6020820190508181035f8301526145588184614319565b905092915050565b5f805f806060858703121561457857614577613f39565b5b5f61458587828801614013565b945050602061459687828801614280565b935050604085013567ffffffffffffffff8111156145b7576145b6613f3d565b5b6145c387828801614033565b925092505092959194509250565b6145da81614228565b81146145e4575f80fd5b50565b5f813590506145f5816145d1565b92915050565b5f602082840312156146105761460f613f39565b5b5f61461d848285016145e7565b91505092915050565b61462f81613ff4565b82525050565b5f6020820190506146485f830184614626565b92915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61468882614309565b810181811067ffffffffffffffff821117156146a7576146a6614652565b5b80604052505050565b5f6146b9613f30565b90506146c5828261467f565b919050565b5f67ffffffffffffffff8211156146e4576146e3614652565b5b6146ed82614309565b9050602081019050919050565b828183375f83830152505050565b5f61471a614715846146ca565b6146b0565b9050828152602081018484840111156147365761473561464e565b5b6147418482856146fa565b509392505050565b5f82601f83011261475d5761475c614027565b5b813561476d848260208601614708565b91505092915050565b5f805f6060848603121561478d5761478c613f39565b5b5f61479a86828701614013565b93505060206147ab86828701614280565b925050604084013567ffffffffffffffff8111156147cc576147cb613f3d565b5b6147d886828701614749565b9150509250925092565b5f805f80604085870312156147fa576147f9613f39565b5b5f85013567ffffffffffffffff81111561481757614816613f3d565b5b61482387828801614033565b9450945050602085013567ffffffffffffffff81111561484657614845613f3d565b5b61485287828801614033565b925092505092959194509250565b61486981613fc1565b8114614873575f80fd5b50565b5f8135905061488481614860565b92915050565b5f80604083850312156148a05761489f613f39565b5b5f6148ad858286016145e7565b92505060206148be85828601614876565b9150509250929050565b5f805f606084860312156148df576148de613f39565b5b5f6148ec86828701614013565b93505060206148fd868287016145e7565b925050604061490e86828701614876565b9150509250925092565b5f61ffff82169050919050565b61492e81614918565b8114614938575f80fd5b50565b5f8135905061494981614925565b92915050565b5f805f6060848603121561496657614965613f39565b5b5f61497386828701614013565b935050602061498486828701614013565b92505060406149958682870161493b565b9150509250925092565b5f805f606084860312156149b6576149b5613f39565b5b5f6149c3868287016145e7565b93505060206149d486828701614013565b92505060406149e5868287016145e7565b9150509250925092565b5f8083601f840112614a0457614a03614027565b5b8235905067ffffffffffffffff811115614a2157614a2061402b565b5b602083019150836020820283011115614a3d57614a3c61402f565b5b9250929050565b5f8060208385031215614a5a57614a59613f39565b5b5f83013567ffffffffffffffff811115614a7757614a76613f3d565b5b614a83858286016149ef565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f82825260208201905092915050565b5f614ad2826142e1565b614adc8185614ab8565b9350614aec8185602086016142fb565b614af581614309565b840191505092915050565b5f614b0b8383614ac8565b905092915050565b5f602082019050919050565b5f614b2982614a8f565b614b338185614a99565b935083602082028501614b4585614aa9565b805f5b85811015614b805784840389528151614b618582614b00565b9450614b6c83614b13565b925060208a01995050600181019050614b48565b50829750879550505050505092915050565b5f6020820190508181035f830152614baa8184614b1f565b905092915050565b5f604082019050614bc55f830185614626565b614bd26020830184614626565b9392505050565b5f8060408385031215614bef57614bee613f39565b5b5f614bfc85828601614013565b9250506020614c0d858286016145e7565b9150509250929050565b5f67ffffffffffffffff82169050919050565b614c3381614c17565b82525050565b5f602082019050614c4c5f830184614c2a565b92915050565b5f805f60408486031215614c6957614c68613f39565b5b5f614c7686828701614013565b935050602084013567ffffffffffffffff811115614c9757614c96613f3d565b5b614ca3868287016149ef565b92509250509250925092565b5f805f60608486031215614cc657614cc5613f39565b5b5f614cd386828701614013565b9350506020614ce486828701613f82565b9250506040614cf5868287016145e7565b9150509250925092565b5f8060408385031215614d1557614d14613f39565b5b5f614d22858286016145e7565b9250506020614d33858286016145e7565b9150509250929050565b5f81905092915050565b5f614d51826142e1565b614d5b8185614d3d565b9350614d6b8185602086016142fb565b80840191505092915050565b5f614d828284614d47565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614dc482614261565b9150614dcf83614261565b9250828203905081811115614de757614de6614d8d565b5b92915050565b5f81905092915050565b5f614e028385614ded565b9350614e0f8385846146fa565b82840190509392505050565b5f614e27828486614df7565b91508190509392505050565b5f82905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680614e8157607f821691505b602082108103614e9457614e93614e3d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302614ef67fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614ebb565b614f008683614ebb565b95508019841693508086168417925050509392505050565b5f819050919050565b5f614f3b614f36614f3184614261565b614f18565b614261565b9050919050565b5f819050919050565b614f5483614f21565b614f68614f6082614f42565b848454614ec7565b825550505050565b5f90565b614f7c614f70565b614f87818484614f4b565b505050565b5b81811015614faa57614f9f5f82614f74565b600181019050614f8d565b5050565b601f821115614fef57614fc081614e9a565b614fc984614eac565b81016020851015614fd8578190505b614fec614fe485614eac565b830182614f8c565b50505b505050565b5f82821c905092915050565b5f61500f5f1984600802614ff4565b1980831691505092915050565b5f6150278383615000565b9150826002028217905092915050565b6150418383614e33565b67ffffffffffffffff81111561505a57615059614652565b5b6150648254614e6a565b61506f828285614fae565b5f601f83116001811461509c575f841561508a578287013590505b615094858261501c565b8655506150fb565b601f1984166150aa86614e9a565b5f5b828110156150d1578489013582556001820191506020850194506020810190506150ac565b868310156150ee57848901356150ea601f891682615000565b8355505b6001600288020188555050505b50505050505050565b5f61510f83856144d8565b935061511c8385846146fa565b61512583614309565b840190509392505050565b5f6040820190508181035f830152615149818688615104565b9050818103602083015261515e818486615104565b905095945050505050565b61517281613f41565b82525050565b5f60208201905061518b5f830184615169565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82905092915050565b5f819050815f5260205f209050919050565b601f82111561521b576151ec816151c8565b6151f584614eac565b81016020851015615204578190505b61521861521085614eac565b830182614f8c565b50505b505050565b61522a83836151be565b67ffffffffffffffff81111561524357615242614652565b5b61524d8254614e6a565b6152588282856151da565b5f601f831160018114615285575f8415615273578287013590505b61527d858261501c565b8655506152e4565b601f198416615293866151c8565b5f5b828110156152ba57848901358255600182019150602085019450602081019050615295565b868310156152d757848901356152d3601f891682615000565b8355505b6001600288020188555050505b50505050505050565b5f6152f883856142eb565b93506153058385846146fa565b61530e83614309565b840190509392505050565b5f6020820190508181035f8301526153328184866152ed565b90509392505050565b5f61534582614c17565b915067ffffffffffffffff820361535f5761535e614d8d565b5b600182019050919050565b5f819050602082019050919050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f6153af8251615379565b80915050919050565b5f6153c2826142e1565b826153cc8461536a565b90506153d7816153a4565b92506014821015615417576154127fffffffffffffffffffffffffffffffffffffffff00000000000000000000000083601403600802614ebb565b831692505b5050919050565b5f819050919050565b61543861543382613ff4565b61541e565b82525050565b5f6154498285615427565b6020820191506154598284615427565b6020820191508190509392505050565b5f6020820190508181035f830152615482818486615104565b90509392505050565b615494826142e1565b67ffffffffffffffff8111156154ad576154ac614652565b5b6154b78254614e6a565b6154c28282856151da565b5f60209050601f8311600181146154f3575f84156154e1578287015190505b6154eb858261501c565b865550615552565b601f198416615501866151c8565b5f5b8281101561552857848901518255600182019150602085019450602081019050615503565b868310156155455784890151615541601f891682615000565b8355505b6001600288020188555050505b505050505050565b5f80fd5b5f80fd5b5f80858511156155755761557461555a565b5b838611156155865761558561555e565b5b6001850283019150848603905094509492505050565b7f496e76616c6964206865782061646472657373000000000000000000000000005f82015250565b5f6155d06013836144d8565b91506155db8261559c565b602082019050919050565b5f6020820190508181035f8301526155fd816155c4565b9050919050565b5f61560f83836151be565b8261561a8135613f41565b9250600482101561565a576156557fffffffff0000000000000000000000000000000000000000000000000000000083600403600802614ebb565b831692505b505092915050565b5f67ffffffffffffffff82111561567c5761567b614652565b5b61568582614309565b9050602081019050919050565b5f6156a461569f84615662565b6146b0565b9050828152602081018484840111156156c0576156bf61464e565b5b6156cb8482856146fa565b509392505050565b5f82601f8301126156e7576156e6614027565b5b81356156f7848260208601615692565b91505092915050565b5f806040838503121561571657615715613f39565b5b5f61572385828601614013565b925050602083013567ffffffffffffffff81111561574457615743613f3d565b5b615750858286016156d3565b9150509250929050565b5f60408201905061576d5f830185614626565b818103602083015261577f81846144e8565b90509392505050565b5f61579a61579584615662565b6146b0565b9050828152602081018484840111156157b6576157b561464e565b5b6157c18482856142fb565b509392505050565b5f82601f8301126157dd576157dc614027565b5b81516157ed848260208601615788565b91505092915050565b5f6020828403121561580b5761580a613f39565b5b5f82015167ffffffffffffffff81111561582857615827613f3d565b5b615834848285016157c9565b91505092915050565b5f819050919050565b61585761585282613f41565b61583d565b82525050565b5f6158688385614d3d565b93506158758385846146fa565b82840190509392505050565b5f61588c8287615846565b60048201915061589c8286615427565b6020820191506158ad82848661585d565b915081905095945050505050565b7f556e737570706f727465642066756e6374696f6e0000000000000000000000005f82015250565b5f6158ef6014836144d8565b91506158fa826158bb565b602082019050919050565b5f6020820190508181035f83015261591c816158e3565b9050919050565b5f61592f82848661585d565b91508190509392505050565b7f5265736f6c7574696f6e206661696c65640000000000000000000000000000005f82015250565b5f61596f6011836144d8565b915061597a8261593b565b602082019050919050565b5f6020820190508181035f83015261599c81615963565b9050919050565b7f455243313135353a2073657474696e6720617070726f76616c207374617475735f8201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b5f6159fd6029836144d8565b9150615a08826159a3565b604082019050919050565b5f6020820190508181035f830152615a2a816159f1565b9050919050565b7f53657474696e672064656c65676174652073746174757320666f722073656c665f82015250565b5f615a656020836144d8565b9150615a7082615a31565b602082019050919050565b5f6020820190508181035f830152615a9281615a59565b9050919050565b5f6040820190508181035f830152615ab18186614319565b90508181036020830152615ac68184866152ed565b9050949350505050565b5f8160601b9050919050565b5f615ae682615ad0565b9050919050565b5f615af782615adc565b9050919050565b615b0f615b0a82614228565b615aed565b82525050565b5f615b208284615afe565b60148201915081905092915050565b5f81519050615b3d816145d1565b92915050565b5f60208284031215615b5857615b57613f39565b5b5f615b6584828501615b2f565b91505092915050565b5f602082019050615b815f8301846142d2565b92915050565b5f615b9182614918565b91505f8203615ba357615ba2614d8d565b5b600182039050919050565b615bb781614918565b82525050565b5f6040820190508181035f830152615bd58185614319565b9050615be46020830184615bae565b9392505050565b5f615bf582614918565b915061ffff8203615c0957615c08614d8d565b5b600182019050919050565b5f6060820190508181035f830152615c2c8186614319565b9050615c3b6020830185615bae565b8181036040830152615c4d8184614319565b9050949350505050565b5f615c6182614261565b9150615c6c83614261565b9250828201905080821115615c8457615c83614d8d565b5b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083356001602003843603038112615cb257615cb1615c8a565b5b80840192508235915067ffffffffffffffff821115615cd457615cd3615c8e565b5b602083019250600182023603831315615cf057615cef615c92565b5b509250929050565b5f615d0383836151be565b82615d0e8135613ff4565b92506020821015615d4e57615d497fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802614ebb565b831692505b505092915050565b7f6d756c746963616c6c3a20416c6c207265636f726473206d75737420686176655f8201527f2061206d61746368696e67206e616d6568617368000000000000000000000000602082015250565b5f615db06034836144d8565b9150615dbb82615d56565b604082019050919050565b5f6020820190508181035f830152615ddd81615da4565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b5f604082019050615e245f8301856142d2565b615e3160208301846142d2565b939250505056fea2646970667358221220666f59a975a4c8228cbda082edea45bee7ea37187b083599527ba9c97134fb6f64736f6c6343000819003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "nonce": "0x3",
+ "chainId": "0x14a34"
+ },
+ "additionalContracts": [],
+ "isFixedGasLimit": false
+ }
+ ],
+ "receipts": [
+ {
+ "status": "0x1",
+ "cumulativeGasUsed": "0x90dd05",
+ "logs": [],
+ "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "type": "0x2",
+ "transactionHash": "0x5349252e11494c3eb04faefde3b94b6a7e8abb41a89af880771ff6ac3bf7882d",
+ "transactionIndex": "0x9",
+ "blockHash": "0x168e9322c12cfb1991ad6c6208ba4be7c06f656991aecd33fec9084b493ad1be",
+ "blockNumber": "0x21c3e15",
+ "gasUsed": "0x507d93",
+ "effectiveGasPrice": "0xe0f3b8",
+ "blobGasUsed": "0x321408",
+ "from": "0x1f3484e712c4657436fdf03f4bc882daea1e3e00",
+ "to": null,
+ "contractAddress": "0xa66c55a6b76967477af18a03f2f12d52251dc2c0",
+ "daFootprintGasScalar": "0x138",
+ "l1BaseFeeScalar": "0x44d",
+ "l1BlobBaseFee": "0x39aec6f64",
+ "l1BlobBaseFeeScalar": "0xa118b",
+ "l1Fee": "0x61c42bfc559d",
+ "l1GasPrice": "0x3a6b8fd",
+ "l1GasUsed": "0x2917e"
+ }
+ ],
+ "libraries": [],
+ "pending": [],
+ "returns": {
+ "resolver": {
+ "internal_type": "contract ConfigResolver",
+ "value": "0xA66c55a6b76967477af18A03F2f12d52251Dc2C0"
+ }
+ },
+ "timestamp": 1766578976219,
+ "chain": 84532,
+ "commit": "c437ed7"
+}
\ No newline at end of file
diff --git a/foundry.lock b/foundry.lock
new file mode 100644
index 0000000..3160688
--- /dev/null
+++ b/foundry.lock
@@ -0,0 +1,8 @@
+{
+ "lib/unruggable-gateways": {
+ "tag": {
+ "name": "v1.3.3",
+ "rev": "8061d898dc86a390689a1d86b3d2690416379e50"
+ }
+ }
+}
\ No newline at end of file
diff --git a/foundry.toml b/foundry.toml
index 6f0ab54..08ab399 100644
--- a/foundry.toml
+++ b/foundry.toml
@@ -1,7 +1,8 @@
[profile.default]
src = "src"
out = "out"
-libs = ["node_modules"]
+libs = ["node_modules", "lib"]
+solc = "0.8.25"
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
diff --git a/lib/unruggable-gateways b/lib/unruggable-gateways
new file mode 160000
index 0000000..8061d89
--- /dev/null
+++ b/lib/unruggable-gateways
@@ -0,0 +1 @@
+Subproject commit 8061d898dc86a390689a1d86b3d2690416379e50
diff --git a/remappings.txt b/remappings.txt
index 5325089..dd26ae9 100644
--- a/remappings.txt
+++ b/remappings.txt
@@ -1,6 +1,6 @@
-forge-std/=node_modules/forge-std/src/
+forge-std/=lib/forge-std/src/
@ensdomains/ens-contracts/=node_modules/@ensdomains/ens-contracts/contracts/
-@unruggable/gateways/=node_modules/@unruggable/gateways/contracts
+@unruggable/=lib/unruggable-gateways/
@openzeppelin/contracts-v5/=node_modules/@openzeppelin/contracts-v5/
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
clones-with-immutable-args/=node_modules/clones-with-immutable-args/
diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol
new file mode 100644
index 0000000..aaada37
--- /dev/null
+++ b/script/Deploy.s.sol
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.25;
+
+import {Script, console} from "forge-std/Script.sol";
+import {ConfigResolver} from "../src/ConfigResolver.sol";
+import {AddressSubnameRegistrar} from "../src/AddressSubnameRegistrar.sol";
+import {L1ConfigResolver} from "../src/L1ConfigResolver.sol";
+import {ENS} from "@ensdomains/ens-contracts/registry/ENS.sol";
+import {INameWrapper} from "@ensdomains/ens-contracts/wrapper/INameWrapper.sol";
+import {IGatewayVerifier} from "@unruggable/contracts/IGatewayVerifier.sol";
+
+/// @title Deploy
+/// @notice Unified deployment script for ENS Config Resolver contracts
+/// @dev Supports deploying ConfigResolver, AddressSubnameRegistrar, and L1ConfigResolver
+///
+/// Usage:
+/// # Deploy ConfigResolver only
+/// forge script script/Deploy.s.sol --sig "deployConfigResolver()" --rpc-url $RPC_URL --account deployer --broadcast --verify
+///
+/// # Deploy ConfigResolver + AddressSubnameRegistrar
+/// PARENT_NODE=$(cast namehash yourname.eth) forge script script/Deploy.s.sol --sig "deployAll()" --rpc-url $RPC_URL --account deployer --broadcast --verify
+///
+/// # Deploy L1ConfigResolver (for reading L2 records from L1)
+/// L2_CONFIG_RESOLVER=0x... forge script script/Deploy.s.sol --sig "deployL1Resolver()" --rpc-url $RPC_URL --account deployer --broadcast --verify
+///
+/// # Deploy L1ConfigResolver with custom verifier/chain (e.g., for non-Base L2s)
+/// VERIFIER=0x... L2_CHAIN_ID=42161 L2_CONFIG_RESOLVER=0x... forge script script/Deploy.s.sol --sig "deployL1Resolver()" --rpc-url $RPC_URL --account deployer --broadcast --verify
+contract Deploy is Script {
+ // ============ Chain IDs ============
+ uint256 constant MAINNET = 1;
+ uint256 constant SEPOLIA = 11155111;
+ uint256 constant BASE_MAINNET = 8453;
+ uint256 constant BASE_SEPOLIA = 84532;
+
+ // ============ ENS Addresses ============
+ // ENS Registry is the same on Mainnet and Sepolia
+ address constant ENS_REGISTRY = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
+ // On L2s without ENS, we use a dummy address (users can only use reverse nodes)
+ address constant DUMMY_ENS = address(0);
+
+ // ============ NameWrapper Addresses ============
+ address constant MAINNET_NAME_WRAPPER =
+ 0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401;
+ address constant SEPOLIA_NAME_WRAPPER =
+ 0x0635513f179D50A207757E05759CbD106d7dFcE8;
+ address constant DUMMY_NAME_WRAPPER = address(0);
+
+ // ============ Gateway Verifier Addresses ============
+ // Sepolia verifier for Base Sepolia
+ IGatewayVerifier constant SEPOLIA_VERIFIER =
+ IGatewayVerifier(0x7F68510F0fD952184ec0b976De429a29A2Ec0FE3);
+ // Mainnet verifier for Base
+ IGatewayVerifier constant MAINNET_VERIFIER =
+ IGatewayVerifier(0x0bC6c539e5fc1fb92F31dE34426f433557A9A5A2);
+
+ // ============ Network Detection ============
+
+ function _getENSRegistry() internal view returns (address) {
+ if (block.chainid == MAINNET || block.chainid == SEPOLIA) {
+ return ENS_REGISTRY;
+ } else if (
+ block.chainid == BASE_MAINNET || block.chainid == BASE_SEPOLIA
+ ) {
+ // L2s don't have ENS - use dummy (only reverse node auth works)
+ return DUMMY_ENS;
+ } else {
+ revert("Unsupported chain");
+ }
+ }
+
+ function _getNameWrapper() internal view returns (address) {
+ if (block.chainid == MAINNET) {
+ return MAINNET_NAME_WRAPPER;
+ } else if (block.chainid == SEPOLIA) {
+ return SEPOLIA_NAME_WRAPPER;
+ } else if (
+ block.chainid == BASE_MAINNET || block.chainid == BASE_SEPOLIA
+ ) {
+ // L2s don't have NameWrapper
+ return DUMMY_NAME_WRAPPER;
+ } else {
+ revert("Unsupported chain");
+ }
+ }
+
+ function _getDefaultVerifier() internal view returns (address) {
+ if (block.chainid == MAINNET) {
+ return address(MAINNET_VERIFIER);
+ } else if (block.chainid == SEPOLIA) {
+ return address(SEPOLIA_VERIFIER);
+ } else {
+ return address(0);
+ }
+ }
+
+ function _getDefaultL2ChainId() internal view returns (uint256) {
+ if (block.chainid == MAINNET) {
+ return BASE_MAINNET;
+ } else if (block.chainid == SEPOLIA) {
+ return BASE_SEPOLIA;
+ } else {
+ return 0;
+ }
+ }
+
+ function _getNetworkName() internal view returns (string memory) {
+ if (block.chainid == MAINNET) {
+ return "Ethereum Mainnet";
+ } else if (block.chainid == SEPOLIA) {
+ return "Sepolia";
+ } else if (block.chainid == BASE_MAINNET) {
+ return "Base Mainnet";
+ } else if (block.chainid == BASE_SEPOLIA) {
+ return "Base Sepolia";
+ } else {
+ return "Unknown";
+ }
+ }
+
+ function _isL2() internal view returns (bool) {
+ return block.chainid == BASE_MAINNET || block.chainid == BASE_SEPOLIA;
+ }
+
+ // ============ Deploy ConfigResolver Only ============
+
+ /// @notice Deploy ConfigResolver contract
+ /// @return resolver The deployed ConfigResolver address
+ function deployConfigResolver() public returns (ConfigResolver resolver) {
+ address ensRegistry = _getENSRegistry();
+ address nameWrapper = _getNameWrapper();
+
+ console.log("");
+ console.log("==========================================");
+ console.log("Deploying ConfigResolver");
+ console.log("==========================================");
+ console.log("Network:", _getNetworkName());
+ console.log("Chain ID:", block.chainid);
+ console.log("ENS Registry:", ensRegistry);
+ console.log("NameWrapper:", nameWrapper);
+ if (_isL2()) {
+ console.log("");
+ console.log("NOTE: On L2, only reverse node authorization works.");
+ console.log(
+ " Users can set records for their own address only."
+ );
+ }
+ console.log("");
+
+ vm.startBroadcast();
+ resolver = new ConfigResolver(
+ ENS(ensRegistry),
+ INameWrapper(nameWrapper)
+ );
+ vm.stopBroadcast();
+
+ console.log("ConfigResolver deployed at:", address(resolver));
+ console.log("");
+ }
+
+ // ============ Deploy ConfigResolver + AddressSubnameRegistrar ============
+
+ /// @notice Deploy ConfigResolver and AddressSubnameRegistrar
+ /// @dev Requires PARENT_NODE environment variable (use `cast namehash yourname.eth`)
+ /// Note: AddressSubnameRegistrar requires ENS, so only works on L1
+ /// @return resolver The deployed ConfigResolver address
+ /// @return registrar The deployed AddressSubnameRegistrar address
+ function deployAll()
+ public
+ returns (ConfigResolver resolver, AddressSubnameRegistrar registrar)
+ {
+ if (_isL2()) {
+ revert(
+ "AddressSubnameRegistrar requires ENS. Use deployConfigResolver() on L2."
+ );
+ }
+
+ bytes32 parentNode = vm.envBytes32("PARENT_NODE");
+ address ensRegistry = _getENSRegistry();
+ address nameWrapper = _getNameWrapper();
+
+ console.log("");
+ console.log("==========================================");
+ console.log("Deploying ConfigResolver + AddressSubnameRegistrar");
+ console.log("==========================================");
+ console.log("Network:", _getNetworkName());
+ console.log("Chain ID:", block.chainid);
+ console.log("ENS Registry:", ensRegistry);
+ console.log("NameWrapper:", nameWrapper);
+ console.log("Parent Node:", vm.toString(parentNode));
+ console.log("");
+
+ vm.startBroadcast();
+
+ // Deploy ConfigResolver first
+ resolver = new ConfigResolver(
+ ENS(ensRegistry),
+ INameWrapper(nameWrapper)
+ );
+ console.log("ConfigResolver deployed at:", address(resolver));
+
+ // Deploy AddressSubnameRegistrar with ConfigResolver as default resolver
+ registrar = new AddressSubnameRegistrar(
+ ENS(ensRegistry),
+ INameWrapper(nameWrapper),
+ parentNode,
+ address(resolver)
+ );
+ console.log("AddressSubnameRegistrar deployed at:", address(registrar));
+
+ vm.stopBroadcast();
+
+ _printNextSteps(
+ parentNode,
+ address(resolver),
+ address(registrar),
+ nameWrapper
+ );
+ }
+
+ // ============ Deploy L1ConfigResolver (for CCIP-Read) ============
+
+ /// @notice Deploy L1ConfigResolver for reading L2 records from L1
+ /// @dev Requires L2_CONFIG_RESOLVER environment variable
+ /// Optional overrides: VERIFIER, L2_CHAIN_ID
+ /// @return resolver The deployed L1ConfigResolver address
+ function deployL1Resolver() public returns (L1ConfigResolver resolver) {
+ address l2ConfigResolver = vm.envAddress("L2_CONFIG_RESOLVER");
+
+ // Get verifier (env override or default for chain)
+ address defaultVerifier = _getDefaultVerifier();
+ address verifierAddr = vm.envOr("VERIFIER", defaultVerifier);
+ require(
+ verifierAddr != address(0),
+ "VERIFIER required: no default for this chain"
+ );
+ IGatewayVerifier verifier = IGatewayVerifier(verifierAddr);
+
+ // Get L2 chain ID (env override or default for chain)
+ uint256 defaultL2ChainId = _getDefaultL2ChainId();
+ uint256 l2ChainId = vm.envOr("L2_CHAIN_ID", defaultL2ChainId);
+ require(
+ l2ChainId != 0,
+ "L2_CHAIN_ID required: no default for this chain"
+ );
+
+ console.log("");
+ console.log("==========================================");
+ console.log("Deploying L1ConfigResolver");
+ console.log("==========================================");
+ console.log("Network:", _getNetworkName());
+ console.log("Chain ID:", block.chainid);
+ console.log("Gateway Verifier:", verifierAddr);
+ if (verifierAddr != defaultVerifier) {
+ console.log(" (overridden via VERIFIER env var)");
+ }
+ console.log("L2 Chain ID:", l2ChainId);
+ if (l2ChainId != defaultL2ChainId) {
+ console.log(" (overridden via L2_CHAIN_ID env var)");
+ }
+ console.log("L2 ConfigResolver:", l2ConfigResolver);
+ console.log("");
+
+ vm.startBroadcast();
+ resolver = new L1ConfigResolver(verifier, l2ChainId, l2ConfigResolver);
+ vm.stopBroadcast();
+
+ console.log("L1ConfigResolver deployed at:", address(resolver));
+ console.log("");
+ }
+
+ // ============ Deploy L1 AddressSubnameRegistrar (for L1 claiming) ============
+
+ /// @notice Deploy AddressSubnameRegistrar on L1 with L1ConfigResolver as default resolver
+ /// @dev This allows users to claim subnames on L1 that resolve via CCIP-Read to L2 records
+ /// Requires PARENT_NODE and L1_CONFIG_RESOLVER environment variables
+ /// @return registrar The deployed AddressSubnameRegistrar address
+ function deployL1Registrar()
+ public
+ returns (AddressSubnameRegistrar registrar)
+ {
+ if (_isL2()) {
+ revert(
+ "AddressSubnameRegistrar for L1 claiming must be deployed on L1"
+ );
+ }
+
+ bytes32 parentNode = vm.envBytes32("PARENT_NODE");
+ address l1ConfigResolver = vm.envAddress("L1_CONFIG_RESOLVER");
+ address ensRegistry = _getENSRegistry();
+ address nameWrapper = _getNameWrapper();
+
+ console.log("");
+ console.log("==========================================");
+ console.log("Deploying L1 AddressSubnameRegistrar");
+ console.log("==========================================");
+ console.log("Network:", _getNetworkName());
+ console.log("Chain ID:", block.chainid);
+ console.log("ENS Registry:", ensRegistry);
+ console.log("NameWrapper:", nameWrapper);
+ console.log("Parent Node:", vm.toString(parentNode));
+ console.log("Default Resolver (L1ConfigResolver):", l1ConfigResolver);
+ console.log("");
+
+ vm.startBroadcast();
+ registrar = new AddressSubnameRegistrar(
+ ENS(ensRegistry),
+ INameWrapper(nameWrapper),
+ parentNode,
+ l1ConfigResolver
+ );
+ vm.stopBroadcast();
+
+ console.log("AddressSubnameRegistrar deployed at:", address(registrar));
+ console.log("");
+
+ _printL1RegistrarNextSteps(
+ parentNode,
+ l1ConfigResolver,
+ address(registrar),
+ nameWrapper
+ );
+ }
+
+ // ============ Deploy Everything (L2 + L1) ============
+
+ /// @notice Deploy all contracts: ConfigResolver, AddressSubnameRegistrar, and L1ConfigResolver
+ /// @dev Requires PARENT_NODE and L2_CONFIG_RESOLVER environment variables
+ /// Note: L1ConfigResolver should typically be deployed on a different chain than ConfigResolver
+ function deployEverything()
+ public
+ returns (
+ ConfigResolver configResolver,
+ AddressSubnameRegistrar registrar,
+ L1ConfigResolver l1Resolver
+ )
+ {
+ (configResolver, registrar) = deployAll();
+ l1Resolver = deployL1Resolver();
+ }
+
+ // ============ Helper Functions ============
+
+ function _printNextSteps(
+ bytes32 parentNode,
+ address resolver,
+ address registrar,
+ address nameWrapper
+ ) internal pure {
+ string memory rpcPlaceholder = "$RPC_URL";
+
+ console.log("");
+ console.log("==========================================");
+ console.log("Next Steps");
+ console.log("==========================================");
+ console.log("");
+ console.log("1. Set ConfigResolver as the resolver for your ENS name:");
+ console.log("");
+ console.log(" # If your name is WRAPPED:");
+ console.log(" cast send", vm.toString(nameWrapper), "\\");
+ console.log(' "setResolver(bytes32,address)" \\');
+ console.log(" ", vm.toString(parentNode), "\\");
+ console.log(" ", vm.toString(resolver), "\\");
+ console.log(" --rpc-url", rpcPlaceholder, "--account ");
+ console.log("");
+ console.log(" # If your name is UNWRAPPED:");
+ console.log(" cast send", vm.toString(ENS_REGISTRY), "\\");
+ console.log(' "setResolver(bytes32,address)" \\');
+ console.log(" ", vm.toString(parentNode), "\\");
+ console.log(" ", vm.toString(resolver), "\\");
+ console.log(" --rpc-url", rpcPlaceholder, "--account ");
+ console.log("");
+ console.log("2. Authorize the registrar to create subnames:");
+ console.log("");
+ console.log(" # If your name is WRAPPED:");
+ console.log(" cast send", vm.toString(nameWrapper), "\\");
+ console.log(' "setApprovalForAll(address,bool)" \\');
+ console.log(" ", vm.toString(registrar), "true \\");
+ console.log(" --rpc-url", rpcPlaceholder, "--account ");
+ console.log("");
+ console.log("3. Users can now:");
+ console.log(" - Set records via their reverse node");
+ console.log(" - Claim their address subname via registrar.claim()");
+ console.log("");
+ }
+
+ function _printL1RegistrarNextSteps(
+ bytes32 parentNode,
+ address l1ConfigResolver,
+ address registrar,
+ address nameWrapper
+ ) internal pure {
+ string memory rpcPlaceholder = "$RPC_URL";
+
+ console.log("");
+ console.log("==========================================");
+ console.log("Next Steps (L1 Registrar with CCIP-Read)");
+ console.log("==========================================");
+ console.log("");
+ console.log("1. Authorize the registrar to create subnames on L1:");
+ console.log("");
+ console.log(" # If your name is WRAPPED:");
+ console.log(" cast send", vm.toString(nameWrapper), "\\");
+ console.log(' "setApprovalForAll(address,bool)" \\');
+ console.log(" ", vm.toString(registrar), "true \\");
+ console.log(" --rpc-url", rpcPlaceholder, "--account ");
+ console.log("");
+ console.log("2. Users can now:");
+ console.log(" - Claim subnames on L1 via registrar.claim()");
+ console.log(" - Subnames resolve via CCIP-Read to L2 records");
+ console.log(
+ " - Users can change their resolver if desired (they own the ENS node)"
+ );
+ console.log("");
+ console.log(
+ "3. To set records, users interact with the L2 ConfigResolver"
+ );
+ console.log(
+ " - Records are stored on L2, read via CCIP-Read from L1"
+ );
+ console.log("");
+ console.log("Default Resolver:", l1ConfigResolver);
+ console.log("Registrar:", registrar);
+ console.log("Parent Node:", vm.toString(parentNode));
+ console.log("");
+ }
+
+ // ============ Default Entry Point ============
+
+ /// @notice Default run function
+ /// @dev On L2: deploys ConfigResolver only
+ /// On L1: deploys ConfigResolver + AddressSubnameRegistrar (requires PARENT_NODE)
+ function run() external {
+ // On L2, just deploy ConfigResolver
+ if (_isL2()) {
+ deployConfigResolver();
+ return;
+ }
+
+ // On L1, check if PARENT_NODE is set
+ try vm.envBytes32("PARENT_NODE") {
+ deployAll();
+ } catch {
+ console.log("");
+ console.log("ERROR: PARENT_NODE environment variable not set");
+ console.log("");
+ console.log("Usage:");
+ console.log(
+ ' PARENT_NODE=$(cast namehash "yourname.eth") forge script script/Deploy.s.sol \\'
+ );
+ console.log(
+ " --rpc-url $RPC_URL --account deployer --broadcast --verify"
+ );
+ console.log("");
+ console.log("Or deploy ConfigResolver only:");
+ console.log(
+ ' forge script script/Deploy.s.sol --sig "deployConfigResolver()" \\'
+ );
+ console.log(
+ " --rpc-url $RPC_URL --account deployer --broadcast --verify"
+ );
+ console.log("");
+ revert("PARENT_NODE not set");
+ }
+ }
+}
diff --git a/script/DeployAddressSubnameRegistrar.s.sol b/script/DeployAddressSubnameRegistrar.s.sol
deleted file mode 100644
index 35b6ef9..0000000
--- a/script/DeployAddressSubnameRegistrar.s.sol
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.17 <0.9.0;
-
-import {Script, console} from "forge-std/Script.sol";
-import {AddressSubnameRegistrar} from "../src/AddressSubnameRegistrar.sol";
-import {ENS} from "@ensdomains/ens-contracts/registry/ENS.sol";
-import {INameWrapper} from "@ensdomains/ens-contracts/wrapper/INameWrapper.sol";
-
-contract DeployAddressSubnameRegistrar is Script {
- // ENS Registry is the same on all networks
- address constant ENS_REGISTRY = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
-
- // Sepolia testnet addresses
- address constant SEPOLIA_NAME_WRAPPER = 0x0635513f179D50A207757E05759CbD106d7dFcE8;
-
- // Mainnet addresses
- address constant MAINNET_NAME_WRAPPER = 0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401;
-
- function run() external {
- // Load configuration from environment
- bytes32 parentNode = vm.envBytes32("PARENT_NODE");
- address defaultResolver = vm.envAddress("DEFAULT_RESOLVER");
-
- // Get chain ID to determine which network we're on
- uint256 chainId = block.chainid;
- address nameWrapper;
-
- if (chainId == 11155111) {
- // Sepolia
- nameWrapper = SEPOLIA_NAME_WRAPPER;
- console.log("Deploying to Sepolia testnet");
- } else if (chainId == 1) {
- // Mainnet
- nameWrapper = MAINNET_NAME_WRAPPER;
- console.log("Deploying to Ethereum mainnet");
- } else {
- revert("Unsupported chain. Use Sepolia (11155111) or Mainnet (1)");
- }
-
- // Start broadcasting transactions
- vm.startBroadcast();
-
- // Deploy AddressSubnameRegistrar
- AddressSubnameRegistrar registrar =
- new AddressSubnameRegistrar(ENS(ENS_REGISTRY), INameWrapper(nameWrapper), parentNode, defaultResolver);
-
- vm.stopBroadcast();
-
- // Log deployment information
- console.log("AddressSubnameRegistrar deployed at:", address(registrar));
- console.log("ENS Registry:", ENS_REGISTRY);
- console.log("NameWrapper:", nameWrapper);
- console.log("Parent Node:", vm.toString(parentNode));
- console.log("Default Resolver:", defaultResolver);
- console.log("Chain ID:", chainId);
- }
-}
diff --git a/script/DeployConfigResolver.s.sol b/script/DeployConfigResolver.s.sol
deleted file mode 100644
index b4ced35..0000000
--- a/script/DeployConfigResolver.s.sol
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity >=0.8.17 <0.9.0;
-
-import {Script, console} from "forge-std/Script.sol";
-import {ConfigResolver} from "../src/ConfigResolver.sol";
-import {ENS} from "@ensdomains/ens-contracts/registry/ENS.sol";
-import {INameWrapper} from "@ensdomains/ens-contracts/wrapper/INameWrapper.sol";
-
-contract DeployConfigResolver is Script {
- // ENS Registry is the same on all networks
- address constant ENS_REGISTRY = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
-
- // Sepolia testnet addresses
- address constant SEPOLIA_NAME_WRAPPER = 0x0635513f179D50A207757E05759CbD106d7dFcE8;
-
- // Mainnet addresses
- address constant MAINNET_NAME_WRAPPER = 0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401;
-
- function run() external {
- // Get chain ID to determine which network we're on
- uint256 chainId = block.chainid;
- address nameWrapper;
-
- if (chainId == 11155111) {
- // Sepolia
- nameWrapper = SEPOLIA_NAME_WRAPPER;
- console.log("Deploying to Sepolia testnet");
- } else if (chainId == 1) {
- // Mainnet
- nameWrapper = MAINNET_NAME_WRAPPER;
- console.log("Deploying to Ethereum mainnet");
- } else {
- revert("Unsupported chain. Use Sepolia (11155111) or Mainnet (1)");
- }
-
- // Start broadcasting transactions using the 'deployer' account
- vm.startBroadcast();
-
- // Deploy ConfigResolver
- ConfigResolver resolver = new ConfigResolver(ENS(ENS_REGISTRY), INameWrapper(nameWrapper));
-
- vm.stopBroadcast();
-
- // Log deployment information
- console.log("ConfigResolver deployed at:", address(resolver));
- console.log("ENS Registry:", ENS_REGISTRY);
- console.log("NameWrapper:", nameWrapper);
- console.log("Chain ID:", chainId);
- console.log("Deployer:", msg.sender);
- }
-}
diff --git a/script/deploy-all.sh b/script/deploy-all.sh
deleted file mode 100755
index cb19ae0..0000000
--- a/script/deploy-all.sh
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/bin/bash
-
-# Deploy ConfigResolver and AddressSubnameRegistrar
-# Usage: ./script/deploy-all.sh
-# Example: ./script/deploy-all.sh sepolia ethconfig.eth
-
-set -e
-
-# Set required environment variables
-export ETHERSCAN_API_KEY="253URMD24CWBW4CNU19BC1T8YMY145DJ9S"
-
-# Parse arguments
-NETWORK=${1:-sepolia}
-PARENT_NAME=${2:-""}
-
-if [ -z "$PARENT_NAME" ]; then
- echo "Usage: ./script/deploy-all.sh "
- echo "Example: ./script/deploy-all.sh sepolia ethconfig.eth"
- exit 1
-fi
-
-# Network configuration
-if [ "$NETWORK" == "sepolia" ]; then
- RPC_URL="${RPC_URL:-https://sepolia.gateway.tenderly.co}"
- CHAIN_ID=11155111
- EXPLORER_URL="https://sepolia.etherscan.io"
- NETWORK_NAME="Sepolia"
-elif [ "$NETWORK" == "mainnet" ]; then
- RPC_URL="${RPC_URL:-https://eth.llamarpc.com}"
- CHAIN_ID=1
- EXPLORER_URL="https://etherscan.io"
- NETWORK_NAME="Ethereum Mainnet"
-else
- echo "Error: Unsupported network. Use 'sepolia' or 'mainnet'"
- exit 1
-fi
-
-# Check if deployer account exists
-if [ ! -f ~/.foundry/keystores/deployer ]; then
- echo "Error: Foundry account 'deployer' not found."
- echo "Create it with: cast wallet import deployer --interactive"
- exit 1
-fi
-
-# Compute parent node
-PARENT_NODE=$(cast namehash "$PARENT_NAME")
-
-echo "=========================================="
-echo "Deploying to $NETWORK_NAME"
-echo "=========================================="
-echo "RPC URL: $RPC_URL"
-echo "Parent Name: $PARENT_NAME"
-echo "Parent Node: $PARENT_NODE"
-echo ""
-
-# Step 1: Deploy ConfigResolver
-echo "Step 1: Deploying ConfigResolver..."
-echo "-----------------------------------"
-
-forge script script/DeployConfigResolver.s.sol:DeployConfigResolver \
- --rpc-url $RPC_URL \
- --account deployer \
- --broadcast \
- --verify \
- --etherscan-api-key $ETHERSCAN_API_KEY \
- -vvv
-
-# Get address from broadcast logs (most reliable method)
-LATEST_RUN="broadcast/DeployConfigResolver.s.sol/$CHAIN_ID/run-latest.json"
-if [ -f "$LATEST_RUN" ]; then
- CONFIG_RESOLVER=$(jq -r '.transactions[] | select(.contractName == "ConfigResolver") | .contractAddress' "$LATEST_RUN" 2>/dev/null | head -1)
-fi
-
-if [ -z "$CONFIG_RESOLVER" ]; then
- echo "Error: Failed to deploy ConfigResolver - no address in broadcast logs"
- exit 1
-fi
-
-echo "ConfigResolver deployed at: $CONFIG_RESOLVER"
-echo ""
-
-# Step 2: Deploy AddressSubnameRegistrar
-echo "Step 2: Deploying AddressSubnameRegistrar..."
-echo "---------------------------------------------"
-
-export PARENT_NODE
-export DEFAULT_RESOLVER=$CONFIG_RESOLVER
-
-forge script script/DeployAddressSubnameRegistrar.s.sol:DeployAddressSubnameRegistrar \
- --rpc-url $RPC_URL \
- --account deployer \
- --broadcast \
- --verify \
- --etherscan-api-key $ETHERSCAN_API_KEY \
- -vvv
-
-# Get address from broadcast logs
-LATEST_RUN="broadcast/DeployAddressSubnameRegistrar.s.sol/$CHAIN_ID/run-latest.json"
-if [ -f "$LATEST_RUN" ]; then
- REGISTRAR=$(jq -r '.transactions[] | select(.contractName == "AddressSubnameRegistrar") | .contractAddress' "$LATEST_RUN" 2>/dev/null | head -1)
-fi
-
-if [ -z "$REGISTRAR" ]; then
- echo "Error: Failed to deploy AddressSubnameRegistrar - no address in broadcast logs"
- exit 1
-fi
-
-echo "AddressSubnameRegistrar deployed at: $REGISTRAR"
-echo ""
-
-# Summary
-echo "=========================================="
-echo "Deployment Complete!"
-echo "=========================================="
-echo ""
-echo "Network: $NETWORK_NAME"
-echo "Parent Name: $PARENT_NAME"
-echo "Parent Node: $PARENT_NODE"
-echo ""
-echo "Contracts:"
-echo " ConfigResolver: $CONFIG_RESOLVER"
-echo " AddressSubnameRegistrar: $REGISTRAR"
-echo ""
-echo "Etherscan:"
-echo " ConfigResolver: $EXPLORER_URL/address/$CONFIG_RESOLVER"
-echo " AddressSubnameRegistrar: $EXPLORER_URL/address/$REGISTRAR"
-echo ""
-echo "=========================================="
-echo "Next Steps"
-echo "=========================================="
-echo ""
-echo "1. Enable wildcard resolution (set ConfigResolver as parent's resolver):"
-echo ""
-echo " # If your name is WRAPPED:"
-if [ "$NETWORK" == "sepolia" ]; then
- NAME_WRAPPER="0x0635513f179D50A207757E05759CbD106d7dFcE8"
-else
- NAME_WRAPPER="0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401"
-fi
-echo " cast send $NAME_WRAPPER \\"
-echo " \"setResolver(bytes32,address)\" \\"
-echo " $PARENT_NODE \\"
-echo " $CONFIG_RESOLVER \\"
-echo " --rpc-url $RPC_URL \\"
-echo " --account "
-echo ""
-echo " # If your name is UNWRAPPED:"
-echo " cast send 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e \\"
-echo " \"setResolver(bytes32,address)\" \\"
-echo " $PARENT_NODE \\"
-echo " $CONFIG_RESOLVER \\"
-echo " --rpc-url $RPC_URL \\"
-echo " --account "
-echo ""
-echo "2. Authorize the registrar to create subnames (for claiming):"
-echo ""
-echo " # If your name is WRAPPED (recommended):"
-echo " cast send $NAME_WRAPPER \\"
-echo " \"setApprovalForAll(address,bool)\" \\"
-echo " $REGISTRAR \\"
-echo " true \\"
-echo " --rpc-url $RPC_URL \\"
-echo " --account "
-echo ""
-echo " # If your name is UNWRAPPED:"
-echo " cast send 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e \\"
-echo " \"setOwner(bytes32,address)\" \\"
-echo " $PARENT_NODE \\"
-echo " $REGISTRAR \\"
-echo " --rpc-url $RPC_URL \\"
-echo " --account "
-echo ""
-echo "3. Users can now:"
-echo " - Set records (works immediately via wildcard):"
-echo " cast send $CONFIG_RESOLVER \"setText(bytes32,string,string)\" \\"
-echo " \$(cast call $CONFIG_RESOLVER \"reverseNode(address)\" \$USER_ADDRESS) \\"
-echo " \"url\" \"https://example.com\" --rpc-url $RPC_URL --account user"
-echo ""
-echo " - Claim their subname (optional, for ENS ownership):"
-echo " cast send $REGISTRAR \"claim()\" --rpc-url $RPC_URL --account user"
-echo ""
diff --git a/script/deploy.sh b/script/deploy.sh
deleted file mode 100755
index b8e00e8..0000000
--- a/script/deploy.sh
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/bin/bash
-
-# Set required environment variables
-export ETHERSCAN_API_KEY="253URMD24CWBW4CNU19BC1T8YMY145DJ9S"
-
-# Network configuration - default to Sepolia
-NETWORK=${1:-sepolia}
-
-if [ "$NETWORK" == "sepolia" ]; then
- RPC_URL="https://sepolia.gateway.tenderly.co"
- CHAIN_ID=11155111
- ENS_REGISTRY="0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
- NAME_WRAPPER="0x0635513f179D50A207757E05759CbD106d7dFcE8"
- EXPLORER_URL="https://sepolia.etherscan.io"
- NETWORK_NAME="Sepolia"
-elif [ "$NETWORK" == "mainnet" ]; then
- RPC_URL="https://eth.llamarpc.com"
- CHAIN_ID=1
- ENS_REGISTRY="0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"
- NAME_WRAPPER="0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401"
- EXPLORER_URL="https://etherscan.io"
- NETWORK_NAME="Ethereum Mainnet"
-else
- echo "Error: Unsupported network. Use 'sepolia' or 'mainnet'"
- exit 1
-fi
-
-# Check if deployer account exists
-if [ ! -f ~/.foundry/keystores/deployer ]; then
- echo "Error: Foundry account 'deployer' not found."
- echo "Keystore file should be at: ~/.foundry/keystores/deployer"
- exit 1
-fi
-
-echo "=========================================="
-echo "Deploying ConfigResolver to $NETWORK_NAME"
-echo "=========================================="
-echo "RPC URL: $RPC_URL"
-echo "Chain ID: $CHAIN_ID"
-echo "ENS Registry: $ENS_REGISTRY"
-echo "NameWrapper: $NAME_WRAPPER"
-echo "Deployer account: deployer (keystore)"
-echo ""
-
-# Deploy the contract
-echo "Deploying contract..."
-DEPLOY_OUTPUT=$(forge script script/DeployConfigResolver.s.sol:DeployConfigResolver \
- --rpc-url $RPC_URL \
- --account deployer \
- --broadcast \
- --verify \
- --etherscan-api-key $ETHERSCAN_API_KEY \
- -vvvv 2>&1)
-
-# Extract the deployed contract address from the output
-CONTRACT_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -o 'ConfigResolver deployed at: 0x[a-fA-F0-9]\{40\}' | sed 's/ConfigResolver deployed at: //' || \
- echo "$DEPLOY_OUTPUT" | grep -o 'Deployed to: 0x[a-fA-F0-9]\{40\}' | sed 's/Deployed to: //' || \
- echo "$DEPLOY_OUTPUT" | grep -A 5 "ConfigResolver" | grep -o '0x[a-fA-F0-9]\{40\}' | head -1)
-
-if [ -z "$CONTRACT_ADDRESS" ]; then
- # Try to get it from broadcast logs
- LATEST_BROADCAST=$(find broadcast/DeployConfigResolver.s.sol -type d -name "$CHAIN_ID" 2>/dev/null | sort -r | head -1)
- if [ -n "$LATEST_BROADCAST" ]; then
- LATEST_RUN=$(find "$LATEST_BROADCAST" -name "run-latest.json" 2>/dev/null)
- if [ -n "$LATEST_RUN" ]; then
- CONTRACT_ADDRESS=$(jq -r '.transactions[] | select(.contractName == "ConfigResolver") | .contractAddress' "$LATEST_RUN" 2>/dev/null | head -1)
- fi
- fi
-fi
-
-if [ -z "$CONTRACT_ADDRESS" ]; then
- echo "Error: Could not extract contract address from deployment output"
- echo "Deployment output:"
- echo "$DEPLOY_OUTPUT"
- exit 1
-fi
-
-echo ""
-echo "=========================================="
-echo "Deployment successful!"
-echo "Contract address: $CONTRACT_ADDRESS"
-echo "=========================================="
-echo ""
-
-# Note: Verification is handled automatically by the --verify flag during deployment
-# Both Etherscan and Sourcify will be notified
-echo "=========================================="
-echo "Verification"
-echo "=========================================="
-echo "Etherscan verification was attempted during deployment via --verify flag"
-echo "Sourcify will automatically pick up the verification from Etherscan"
-echo ""
-echo "Contract address: $CONTRACT_ADDRESS"
-echo "Etherscan: $EXPLORER_URL/address/$CONTRACT_ADDRESS"
-echo "Sourcify: https://sourcify.dev/#/lookup/$CONTRACT_ADDRESS"
-echo ""
-
diff --git a/src/AddressSubnameRegistrar.sol b/src/AddressSubnameRegistrar.sol
index 29e5669..54aff2b 100644
--- a/src/AddressSubnameRegistrar.sol
+++ b/src/AddressSubnameRegistrar.sol
@@ -1,5 +1,5 @@
//SPDX-License-Identifier: MIT
-pragma solidity >=0.8.17 <0.9.0;
+pragma solidity ^0.8.25;
import "@ensdomains/ens-contracts/registry/ENS.sol";
import {INameWrapper} from "@ensdomains/ens-contracts/wrapper/INameWrapper.sol";
@@ -87,11 +87,13 @@ contract AddressSubnameRegistrar {
/// @notice Get the label (hex address) for a given address
/// @param addr The address
- /// @return The lowercase hex string (40 characters, no 0x prefix)
+ /// @return The lowercase hex string (42 characters, with 0x prefix)
function getLabel(address addr) public pure returns (string memory) {
- bytes memory ret = new bytes(40);
+ bytes memory ret = new bytes(42);
+ ret[0] = "0";
+ ret[1] = "x";
uint160 addrVal = uint160(addr);
- for (uint256 i = 40; i > 0;) {
+ for (uint256 i = 42; i > 2;) {
unchecked {
i--;
ret[i] = bytes1(uint8(lookup[addrVal & 0xf]));
@@ -145,10 +147,14 @@ contract AddressSubnameRegistrar {
ens.setSubnodeRecord(parentNode, labelHash, owner, defaultResolver, 0);
}
- /// @dev Compute the keccak256 hash of the lowercase hex representation of an address
+ /// @dev Compute the keccak256 hash of the lowercase hex representation of an address with 0x prefix
function sha3HexAddress(address addr) internal pure returns (bytes32 ret) {
assembly {
- for { let i := 40 } gt(i, 0) {} {
+ // Store "0x" prefix at positions 0-1
+ mstore8(0, 0x30) // '0' = 0x30
+ mstore8(1, 0x78) // 'x' = 0x78
+ // Store hex address starting at position 2
+ for { let i := 42 } gt(i, 2) {} {
i := sub(i, 1)
mstore8(i, byte(and(addr, 0xf), lookup))
addr := div(addr, 0x10)
@@ -156,7 +162,7 @@ contract AddressSubnameRegistrar {
mstore8(i, byte(and(addr, 0xf), lookup))
addr := div(addr, 0x10)
}
- ret := keccak256(0, 40)
+ ret := keccak256(0, 42)
}
}
}
diff --git a/src/ConfigResolver.sol b/src/ConfigResolver.sol
index d1d27fe..6fc1f62 100644
--- a/src/ConfigResolver.sol
+++ b/src/ConfigResolver.sol
@@ -1,5 +1,5 @@
//SPDX-License-Identifier: MIT
-pragma solidity >=0.8.17 <0.9.0;
+pragma solidity ^0.8.25;
import "@ensdomains/ens-contracts/registry/ENS.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/ABIResolver.sol";
@@ -125,7 +125,7 @@ contract ConfigResolver is
return owner == msg.sender || isApprovedForAll(owner, msg.sender) || isApprovedFor(owner, node, msg.sender);
}
- /// @dev ENSIP-10 wildcard resolution. Resolves subnames like .parent.eth
+ /// @dev ENSIP-10 wildcard resolution. Resolves subnames like 0x.parent.eth
/// without requiring them to be claimed in ENS, and also supports standard resolution
/// for manually created names.
/// @param name The DNS-encoded name to resolve
@@ -135,11 +135,16 @@ contract ConfigResolver is
// Extract the first label length
uint256 labelLen = uint8(name[0]);
- // If this is a 40-char hex address label, handle wildcard resolution
- if (labelLen == 40) {
- // Parse the hex address from the label
- bytes memory label = name[1:41];
- (address resolvedAddr, bool valid) = label.hexToAddress(0, 40);
+ // If this is a 42-char hex address label (0x + 40 hex chars), handle wildcard resolution
+ if (labelLen == 42) {
+ // Parse the hex address from the label (skip "0x" prefix)
+ bytes memory label = name[1:43];
+ // Verify "0x" prefix
+ if (label[0] != 0x30 || label[1] != 0x78) {
+ // '0' = 0x30, 'x' = 0x78
+ revert("Invalid address prefix");
+ }
+ (address resolvedAddr, bool valid) = label.hexToAddress(2, 42);
if (!valid) {
revert("Invalid hex address");
}
diff --git a/src/IL1ConfigResolver.sol b/src/IL1ConfigResolver.sol
new file mode 100644
index 0000000..15fc604
--- /dev/null
+++ b/src/IL1ConfigResolver.sol
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.25;
+
+/// @title IL1ConfigResolver
+/// @notice Interface for L1 resolvers that read ENS records from an L2 ConfigResolver
+interface IL1ConfigResolver {
+ /// @notice Returns the chain ID of the L2 where the ConfigResolver is deployed
+ /// @return The L2 chain ID
+ function l2ChainId() external view returns (uint256);
+
+ /// @notice Returns the address of the ConfigResolver on L2
+ /// @return The L2 ConfigResolver address
+ function l2ConfigResolver() external view returns (address);
+}
diff --git a/src/L1ConfigResolver.sol b/src/L1ConfigResolver.sol
new file mode 100644
index 0000000..ce99a45
--- /dev/null
+++ b/src/L1ConfigResolver.sol
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.25;
+
+import {
+ GatewayFetcher,
+ GatewayRequest
+} from "@unruggable/contracts/GatewayFetcher.sol";
+import {GatewayFetchTarget} from "@unruggable/contracts/GatewayFetchTarget.sol";
+import {IGatewayVerifier} from "@unruggable/contracts/IGatewayVerifier.sol";
+import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
+
+// ENS Resolver Interfaces
+import {
+ IAddrResolver
+} from "@ensdomains/ens-contracts/resolvers/profiles/IAddrResolver.sol";
+import {
+ IAddressResolver
+} from "@ensdomains/ens-contracts/resolvers/profiles/IAddressResolver.sol";
+import {
+ ITextResolver
+} from "@ensdomains/ens-contracts/resolvers/profiles/ITextResolver.sol";
+import {
+ IContentHashResolver
+} from "@ensdomains/ens-contracts/resolvers/profiles/IContentHashResolver.sol";
+import {
+ IExtendedResolver
+} from "@ensdomains/ens-contracts/resolvers/profiles/IExtendedResolver.sol";
+import {IL1ConfigResolver} from "./IL1ConfigResolver.sol";
+
+/// @title L1ConfigResolver
+/// @notice An L1 resolver that reads ENS records from the ConfigResolver deployed on L2 (Base)
+/// @dev Uses CCIP-Read (EIP-3668) via Unruggable Gateways to trustlessly read L2 storage
+contract L1ConfigResolver is
+ GatewayFetchTarget,
+ IERC165,
+ IExtendedResolver,
+ IL1ConfigResolver
+{
+ using GatewayFetcher for GatewayRequest;
+
+ // ============ Errors ============
+ error UnsupportedSelector(bytes4 selector);
+
+ // ============ Constants ============
+
+ // Storage slot constants for ConfigResolver
+ // Verified via `forge inspect ConfigResolver storage`
+ uint256 constant SLOT_RECORD_VERSIONS = 0;
+ uint256 constant SLOT_VERSIONABLE_ADDRESSES = 2;
+ uint256 constant SLOT_VERSIONABLE_HASHES = 3;
+ uint256 constant SLOT_VERSIONABLE_TEXTS = 10;
+
+ // Coin type for Ethereum (SLIP-44)
+ uint256 constant COIN_TYPE_ETH = 60;
+
+ // ============ Immutables ============
+ IGatewayVerifier public immutable verifier;
+ uint256 public immutable l2ChainId;
+ address public immutable l2ConfigResolver;
+
+ // ============ Constructor ============
+ constructor(
+ IGatewayVerifier _verifier,
+ uint256 _l2ChainId,
+ address _l2ConfigResolver
+ ) {
+ verifier = _verifier;
+ l2ChainId = _l2ChainId;
+ l2ConfigResolver = _l2ConfigResolver;
+ }
+
+ // ============ ERC-165 ============
+ function supportsInterface(
+ bytes4 interfaceId
+ ) external pure override returns (bool) {
+ return
+ interfaceId == type(IERC165).interfaceId ||
+ interfaceId == type(IExtendedResolver).interfaceId ||
+ interfaceId == type(IAddrResolver).interfaceId ||
+ interfaceId == type(IAddressResolver).interfaceId ||
+ interfaceId == type(ITextResolver).interfaceId ||
+ interfaceId == type(IContentHashResolver).interfaceId ||
+ interfaceId == type(IL1ConfigResolver).interfaceId;
+ }
+
+ // ============ ENSIP-10 Extended Resolver ============
+
+ /// @notice Resolves ENS records by reading from the L2 ConfigResolver
+ /// @dev The DNS-encoded name parameter is unused for direct resolution
+ /// @param data The ABI-encoded function call (selector + args)
+ /// @return The ABI-encoded result
+ function resolve(
+ bytes calldata,
+ bytes calldata data
+ ) external view override returns (bytes memory) {
+ bytes4 selector = bytes4(data);
+
+ // Decode the node from calldata
+ bytes32 node;
+ if (
+ selector == IAddrResolver.addr.selector ||
+ selector == IContentHashResolver.contenthash.selector
+ ) {
+ node = abi.decode(data[4:], (bytes32));
+ } else if (selector == IAddressResolver.addr.selector) {
+ (node, ) = abi.decode(data[4:], (bytes32, uint256));
+ } else if (selector == ITextResolver.text.selector) {
+ (node, ) = abi.decode(data[4:], (bytes32, string));
+ } else {
+ revert UnsupportedSelector(selector);
+ }
+
+ // Build the gateway request
+ GatewayRequest memory req = _buildRequest(node, data);
+
+ // Execute CCIP-Read fetch
+ fetch(
+ verifier,
+ req,
+ this.resolveCallback.selector,
+ data,
+ new string[](0)
+ );
+ }
+
+ /// @notice Callback that receives verified L2 data
+ /// @param values The array of values read from L2
+ /// @param exitCode The exit code (0 = success)
+ /// @param data The original calldata passed through
+ /// @return The ABI-encoded result
+ function resolveCallback(
+ bytes[] calldata values,
+ uint8 exitCode,
+ bytes calldata data
+ ) external pure returns (bytes memory) {
+ // Exit code != 0 means record not found or error
+ if (exitCode != 0) {
+ return _emptyResponse(bytes4(data));
+ }
+
+ bytes4 selector = bytes4(data);
+
+ if (selector == IAddrResolver.addr.selector) {
+ // addr(bytes32) returns address
+ bytes memory addrBytes = values[0];
+ if (addrBytes.length == 0) {
+ return abi.encode(address(0));
+ }
+ return abi.encode(address(bytes20(addrBytes)));
+ } else if (selector == IAddressResolver.addr.selector) {
+ // addr(bytes32, uint256) returns bytes
+ return abi.encode(values[0]);
+ } else if (selector == ITextResolver.text.selector) {
+ // text(bytes32, string) returns string
+ return abi.encode(string(values[0]));
+ } else if (selector == IContentHashResolver.contenthash.selector) {
+ // contenthash(bytes32) returns bytes
+ return abi.encode(values[0]);
+ }
+
+ return new bytes(0);
+ }
+
+ // ============ Direct Resolution Methods ============
+
+ /// @notice Get the ETH address for a node
+ /// @param node The ENS node hash
+ /// @return The ETH address
+ function addr(bytes32 node) external view returns (address) {
+ GatewayRequest memory req = _buildAddrRequest(node, COIN_TYPE_ETH);
+ fetch(
+ verifier,
+ req,
+ this.addrCallback.selector,
+ abi.encode(node),
+ new string[](0)
+ );
+ }
+
+ /// @notice Callback for addr()
+ function addrCallback(
+ bytes[] calldata values,
+ uint8 exitCode,
+ bytes calldata
+ ) external pure returns (address) {
+ if (exitCode != 0 || values[0].length == 0) {
+ return address(0);
+ }
+ return address(bytes20(values[0]));
+ }
+
+ /// @notice Get a text record for a node
+ /// @param node The ENS node hash
+ /// @param key The text record key
+ /// @return The text record value
+ function text(
+ bytes32 node,
+ string calldata key
+ ) external view returns (string memory) {
+ GatewayRequest memory req = _buildTextRequest(node, key);
+ fetch(verifier, req, this.textCallback.selector, "", new string[](0));
+ }
+
+ /// @notice Callback for text()
+ function textCallback(
+ bytes[] calldata values,
+ uint8 exitCode,
+ bytes calldata
+ ) external pure returns (string memory) {
+ if (exitCode != 0 || values[0].length == 0) {
+ return "";
+ }
+ return string(values[0]);
+ }
+
+ /// @notice Get the contenthash for a node
+ /// @param node The ENS node hash
+ /// @return The contenthash bytes
+ function contenthash(bytes32 node) external view returns (bytes memory) {
+ GatewayRequest memory req = _buildContenthashRequest(node);
+ fetch(
+ verifier,
+ req,
+ this.contenthashCallback.selector,
+ "",
+ new string[](0)
+ );
+ }
+
+ /// @notice Callback for contenthash()
+ function contenthashCallback(
+ bytes[] calldata values,
+ uint8 exitCode,
+ bytes calldata
+ ) external pure returns (bytes memory) {
+ if (exitCode != 0) {
+ return "";
+ }
+ return values[0];
+ }
+
+ // ============ Internal Request Builders ============
+
+ /// @notice Build a gateway request based on the selector
+ function _buildRequest(
+ bytes32 node,
+ bytes calldata data
+ ) internal view returns (GatewayRequest memory) {
+ bytes4 selector = bytes4(data);
+
+ if (selector == IAddrResolver.addr.selector) {
+ return _buildAddrRequest(node, COIN_TYPE_ETH);
+ } else if (selector == IAddressResolver.addr.selector) {
+ (, uint256 coinType) = abi.decode(data[4:], (bytes32, uint256));
+ return _buildAddrRequest(node, coinType);
+ } else if (selector == ITextResolver.text.selector) {
+ (, string memory key) = abi.decode(data[4:], (bytes32, string));
+ return _buildTextRequest(node, key);
+ } else if (selector == IContentHashResolver.contenthash.selector) {
+ return _buildContenthashRequest(node);
+ }
+
+ revert UnsupportedSelector(selector);
+ }
+
+ /// @notice Build a request to read an address record
+ /// @dev Reads versionable_addresses[recordVersions[node]][node][coinType]
+ function _buildAddrRequest(
+ bytes32 node,
+ uint256 coinType
+ ) internal view returns (GatewayRequest memory req) {
+ req = GatewayFetcher.newRequest(1).setTarget(l2ConfigResolver);
+
+ // Step 1: Read recordVersions[node] and push to stack
+ // recordVersions is mapping(bytes32 => uint64) at slot 0
+ req = req.setSlot(SLOT_RECORD_VERSIONS).push(node).follow().read();
+
+ // Step 2: Now stack has the version, use it to navigate versionable_addresses
+ // versionable_addresses[version][node][coinType]
+ req = req.setSlot(SLOT_VERSIONABLE_ADDRESSES);
+ // follow() uses top of stack (version) as key
+ req = req.follow();
+ // Now push node and follow
+ req = req.push(node).follow();
+ // Now push coinType and follow
+ req = req.push(coinType).follow();
+ // Read the bytes value (dynamic bytes)
+ req = req.readBytes().setOutput(0);
+ }
+
+ /// @notice Build a request to read a text record
+ /// @dev Reads versionable_texts[recordVersions[node]][node][key]
+ function _buildTextRequest(
+ bytes32 node,
+ string memory key
+ ) internal view returns (GatewayRequest memory req) {
+ req = GatewayFetcher.newRequest(1).setTarget(l2ConfigResolver);
+
+ // Step 1: Read recordVersions[node] and push to stack
+ req = req.setSlot(SLOT_RECORD_VERSIONS).push(node).follow().read();
+
+ // Step 2: Navigate versionable_texts[version][node][key]
+ req = req.setSlot(SLOT_VERSIONABLE_TEXTS);
+ // follow() uses top of stack (version) as key
+ req = req.follow();
+ // Push node and follow
+ req = req.push(node).follow();
+ // Push key (string) and follow
+ req = req.push(key).follow();
+ // Read the string value (dynamic bytes)
+ req = req.readBytes().setOutput(0);
+ }
+
+ /// @notice Build a request to read a contenthash
+ /// @dev Reads versionable_hashes[recordVersions[node]][node]
+ function _buildContenthashRequest(
+ bytes32 node
+ ) internal view returns (GatewayRequest memory req) {
+ req = GatewayFetcher.newRequest(1).setTarget(l2ConfigResolver);
+
+ // Step 1: Read recordVersions[node] and push to stack
+ req = req.setSlot(SLOT_RECORD_VERSIONS).push(node).follow().read();
+
+ // Step 2: Navigate versionable_hashes[version][node]
+ req = req.setSlot(SLOT_VERSIONABLE_HASHES);
+ // follow() uses top of stack (version) as key
+ req = req.follow();
+ // Push node and follow
+ req = req.push(node).follow();
+ // Read the bytes value (dynamic bytes)
+ req = req.readBytes().setOutput(0);
+ }
+
+ /// @notice Return an empty response for the given selector
+ function _emptyResponse(
+ bytes4 selector
+ ) internal pure returns (bytes memory) {
+ if (selector == IAddrResolver.addr.selector) {
+ return abi.encode(address(0));
+ } else if (selector == IAddressResolver.addr.selector) {
+ return abi.encode(new bytes(0));
+ } else if (selector == ITextResolver.text.selector) {
+ return abi.encode("");
+ } else if (selector == IContentHashResolver.contenthash.selector) {
+ return abi.encode(new bytes(0));
+ }
+ return new bytes(0);
+ }
+}
diff --git a/test/AddressSubnameRegistrar.t.sol b/test/AddressSubnameRegistrar.t.sol
index 184004b..102b7ad 100644
--- a/test/AddressSubnameRegistrar.t.sol
+++ b/test/AddressSubnameRegistrar.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.13;
+pragma solidity ^0.8.25;
import {Test, console} from "forge-std/Test.sol";
import {AddressSubnameRegistrar} from "../src/AddressSubnameRegistrar.sol";
@@ -63,14 +63,14 @@ contract AddressSubnameRegistrarTest is Test {
// Log the label for verification
string memory label = registrar.getLabel(alice);
console.log("Alice's subname label:", label);
- // Should be: 8d25687829d6b85d9e0020b8c89e3ca24de20a89
+ // Should be: 0x8d25687829d6b85d9e0020b8c89e3ca24de20a89
}
function test_LabelIsNormalizedLowercase() public {
// The address 0x8d25687829D6b85d9e0020B8c89e3Ca24dE20a89
- // should produce label: 8d25687829d6b85d9e0020b8c89e3ca24de20a89
+ // should produce label: 0x8d25687829d6b85d9e0020b8c89e3ca24de20a89
string memory label = registrar.getLabel(alice);
- assertEq(label, "8d25687829d6b85d9e0020b8c89e3ca24de20a89");
+ assertEq(label, "0x8d25687829d6b85d9e0020b8c89e3ca24de20a89");
}
function test_CannotClaimSameSubnameTwice() public {
diff --git a/test/ConfigResolver.t.sol b/test/ConfigResolver.t.sol
index 070884d..edd93bf 100644
--- a/test/ConfigResolver.t.sol
+++ b/test/ConfigResolver.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.13;
+pragma solidity ^0.8.25;
import {Test} from "forge-std/Test.sol";
import {ConfigResolver} from "../src/ConfigResolver.sol";
@@ -279,37 +279,199 @@ contract ConfigResolverTest is Test {
}
function test_WildcardResolveInvalidHex() public {
- // Test with invalid hex characters (40 chars but not valid hex)
- // "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" - 40 z's
+ // Test with invalid hex characters (42 chars with 0x prefix but invalid hex after)
+ // "0xzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" - 0x + 40 z's
bytes memory invalidName =
- hex"287a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a04746573740365746800";
+ hex"2a30787a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a04746573740365746800";
bytes memory data = abi.encodeWithSelector(IAddrResolver.addr.selector, bytes32(0));
vm.expectRevert("Invalid hex address");
resolver.resolve(invalidName, data);
}
- // Helper to build DNS-encoded name for address.parent.tld
+ function test_WildcardResolveChecksummedAddress() public {
+ // Test that checksummed (mixed case) addresses resolve correctly
+ // Using a well-known checksummed address format
+ address testAddr = 0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B;
+
+ // Build DNS name with checksummed address (mixed case)
+ bytes memory checksummedName = _buildDnsNameWithChecksummedAddress(testAddr, "test", "eth");
+
+ // Build the addr(bytes32) call data
+ bytes memory data = abi.encodeWithSelector(IAddrResolver.addr.selector, bytes32(0));
+
+ // Call resolve - should work with checksummed address
+ bytes memory result = resolver.resolve(checksummedName, data);
+
+ // Decode and verify
+ address resolved = abi.decode(result, (address));
+ assertEq(resolved, testAddr);
+ }
+
+ function test_WildcardResolveChecksummedAndLowercaseReturnSameResult() public {
+ // Verify that both checksummed and lowercase addresses resolve to the same result
+ address testAddr = 0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B;
+
+ // Set up a text record for this address
+ bytes32 addrReverseNode = resolver.reverseNode(testAddr);
+
+ // We need to give testAddr ownership of their reverse node
+ vm.prank(testAddr);
+ reverseRegistrar.claimForAddr(testAddr, testAddr, address(resolver));
+
+ vm.prank(testAddr);
+ resolver.setText(addrReverseNode, "url", "https://vitalik.example.com");
+
+ // Build DNS names with both formats
+ bytes memory lowercaseName = _buildDnsName(testAddr, "test", "eth");
+ bytes memory checksummedName = _buildDnsNameWithChecksummedAddress(testAddr, "test", "eth");
+
+ bytes memory textData = abi.encodeWithSelector(ITextResolver.text.selector, bytes32(0), "url");
+
+ // Both should return the same text record
+ bytes memory result1 = resolver.resolve(lowercaseName, textData);
+ bytes memory result2 = resolver.resolve(checksummedName, textData);
+
+ assertEq(abi.decode(result1, (string)), "https://vitalik.example.com");
+ assertEq(abi.decode(result2, (string)), "https://vitalik.example.com");
+
+ // Both should also return the same address
+ bytes memory addrData = abi.encodeWithSelector(IAddrResolver.addr.selector, bytes32(0));
+
+ bytes memory addrResult1 = resolver.resolve(lowercaseName, addrData);
+ bytes memory addrResult2 = resolver.resolve(checksummedName, addrData);
+
+ assertEq(abi.decode(addrResult1, (address)), testAddr);
+ assertEq(abi.decode(addrResult2, (address)), testAddr);
+ }
+
+ function test_WildcardResolveUppercaseAddress() public view {
+ // Test with fully uppercase address (another edge case)
+ address testAddr = 0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B;
+
+ // Build DNS name with uppercase address
+ bytes memory uppercaseName = _buildDnsNameWithUppercaseAddress(testAddr, "test", "eth");
+
+ // Build the addr(bytes32) call data
+ bytes memory data = abi.encodeWithSelector(IAddrResolver.addr.selector, bytes32(0));
+
+ // Call resolve - should work with uppercase address
+ bytes memory result = resolver.resolve(uppercaseName, data);
+
+ // Decode and verify
+ address resolved = abi.decode(result, (address));
+ assertEq(resolved, testAddr);
+ }
+
+ // Helper to build DNS-encoded name for 0xaddress.parent.tld
function _buildDnsName(address addr, string memory parent, string memory tld) private pure returns (bytes memory) {
bytes memory hexAddr = _addressToHexBytes(addr);
bytes memory parentBytes = bytes(parent);
bytes memory tldBytes = bytes(tld);
- // Format: \x28<40-char-hex>\x\x\x00
+ // Format: \x2a<42-char-hex-with-0x>\x\x\x00
return abi.encodePacked(
- uint8(40), hexAddr, uint8(parentBytes.length), parentBytes, uint8(tldBytes.length), tldBytes, uint8(0)
+ uint8(42), hexAddr, uint8(parentBytes.length), parentBytes, uint8(tldBytes.length), tldBytes, uint8(0)
);
}
- // Helper to convert address to lowercase hex bytes (40 chars, no 0x)
+ // Helper to convert address to lowercase hex bytes (42 chars, with 0x prefix)
function _addressToHexBytes(address addr) private pure returns (bytes memory) {
- bytes memory result = new bytes(40);
+ bytes memory result = new bytes(42);
bytes memory hexChars = "0123456789abcdef";
+ result[0] = "0";
+ result[1] = "x";
+ for (uint256 i = 0; i < 20; i++) {
+ uint8 b = uint8(uint160(addr) >> (8 * (19 - i)));
+ result[2 + i * 2] = hexChars[b >> 4];
+ result[2 + i * 2 + 1] = hexChars[b & 0x0f];
+ }
+
+ return result;
+ }
+
+ // Helper to build DNS-encoded name with checksummed address
+ function _buildDnsNameWithChecksummedAddress(address addr, string memory parent, string memory tld)
+ private
+ pure
+ returns (bytes memory)
+ {
+ bytes memory hexAddr = _addressToChecksummedHexBytes(addr);
+ bytes memory parentBytes = bytes(parent);
+ bytes memory tldBytes = bytes(tld);
+
+ return abi.encodePacked(
+ uint8(42), hexAddr, uint8(parentBytes.length), parentBytes, uint8(tldBytes.length), tldBytes, uint8(0)
+ );
+ }
+
+ // Helper to build DNS-encoded name with uppercase address
+ function _buildDnsNameWithUppercaseAddress(address addr, string memory parent, string memory tld)
+ private
+ pure
+ returns (bytes memory)
+ {
+ bytes memory hexAddr = _addressToUppercaseHexBytes(addr);
+ bytes memory parentBytes = bytes(parent);
+ bytes memory tldBytes = bytes(tld);
+
+ return abi.encodePacked(
+ uint8(42), hexAddr, uint8(parentBytes.length), parentBytes, uint8(tldBytes.length), tldBytes, uint8(0)
+ );
+ }
+
+ // Helper to convert address to checksummed hex bytes (EIP-55) with 0x prefix
+ function _addressToChecksummedHexBytes(address addr) private pure returns (bytes memory) {
+ bytes memory result = new bytes(42);
+ bytes memory hexCharsLower = "0123456789abcdef";
+
+ result[0] = "0";
+ result[1] = "x";
+
+ // First, create lowercase hex string (without 0x for hashing)
+ bytes memory lowercase = new bytes(40);
+ for (uint256 i = 0; i < 20; i++) {
+ uint8 b = uint8(uint160(addr) >> (8 * (19 - i)));
+ lowercase[i * 2] = hexCharsLower[b >> 4];
+ lowercase[i * 2 + 1] = hexCharsLower[b & 0x0f];
+ }
+
+ // Hash the lowercase address for checksum
+ bytes32 hash = keccak256(lowercase);
+
+ // Apply checksum (EIP-55)
+ for (uint256 i = 0; i < 40; i++) {
+ uint8 hashNibble = uint8(hash[i / 2]);
+ if (i % 2 == 0) {
+ hashNibble = hashNibble >> 4;
+ } else {
+ hashNibble = hashNibble & 0x0f;
+ }
+
+ uint8 charCode = uint8(lowercase[i]);
+ // If it's a letter (a-f) and hash nibble >= 8, uppercase it
+ if (charCode >= 97 && charCode <= 102 && hashNibble >= 8) {
+ result[2 + i] = bytes1(charCode - 32); // Convert to uppercase
+ } else {
+ result[2 + i] = lowercase[i];
+ }
+ }
+
+ return result;
+ }
+
+ // Helper to convert address to uppercase hex bytes (42 chars, with 0x prefix)
+ function _addressToUppercaseHexBytes(address addr) private pure returns (bytes memory) {
+ bytes memory result = new bytes(42);
+ bytes memory hexChars = "0123456789ABCDEF";
+
+ result[0] = "0";
+ result[1] = "x";
for (uint256 i = 0; i < 20; i++) {
uint8 b = uint8(uint160(addr) >> (8 * (19 - i)));
- result[i * 2] = hexChars[b >> 4];
- result[i * 2 + 1] = hexChars[b & 0x0f];
+ result[2 + i * 2] = hexChars[b >> 4];
+ result[2 + i * 2 + 1] = hexChars[b & 0x0f];
}
return result;
diff --git a/test/L1ConfigResolver.t.sol b/test/L1ConfigResolver.t.sol
new file mode 100644
index 0000000..8bdda5b
--- /dev/null
+++ b/test/L1ConfigResolver.t.sol
@@ -0,0 +1,610 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.25;
+
+import {Test, console} from "forge-std/Test.sol";
+import {L1ConfigResolver} from "../src/L1ConfigResolver.sol";
+import {IL1ConfigResolver} from "../src/IL1ConfigResolver.sol";
+import {ConfigResolver} from "../src/ConfigResolver.sol";
+import {ENS} from "@ensdomains/ens-contracts/registry/ENS.sol";
+import {INameWrapper} from "@ensdomains/ens-contracts/wrapper/INameWrapper.sol";
+import {IGatewayVerifier} from "@unruggable/contracts/IGatewayVerifier.sol";
+import {
+ GatewayRequest,
+ GatewayOP
+} from "@unruggable/contracts/GatewayRequest.sol";
+import {GatewayFetcher} from "@unruggable/contracts/GatewayFetcher.sol";
+import {
+ GatewayFetchTarget,
+ OffchainLookup
+} from "@unruggable/contracts/GatewayFetchTarget.sol";
+
+/// @title MockGatewayVerifier
+/// @notice A mock verifier that returns pre-computed values for testing
+contract MockGatewayVerifier is IGatewayVerifier {
+ function getLatestContext() external view returns (bytes memory) {
+ return abi.encode(block.number);
+ }
+
+ function gatewayURLs() external pure returns (string[] memory urls) {
+ urls = new string[](1);
+ urls[0] = "https://mock.gateway/";
+ }
+
+ /// @notice Returns values from the proof (which contains pre-computed values in tests)
+ function getStorageValues(
+ bytes memory,
+ GatewayRequest memory,
+ bytes memory proof
+ ) external pure returns (bytes[] memory values, uint8 exitCode) {
+ (values, exitCode) = abi.decode(proof, (bytes[], uint8));
+ }
+}
+
+/// @title L1ConfigResolverTest
+/// @notice End-to-end tests for L1ConfigResolver reading from ConfigResolver
+contract L1ConfigResolverTest is Test {
+ using GatewayFetcher for GatewayRequest;
+
+ // Contracts
+ ConfigResolver public configResolver;
+ L1ConfigResolver public l1Resolver;
+ MockGatewayVerifier public mockVerifier;
+
+ // Test data
+ address public user = address(0x1234567890123456789012345678901234567890);
+ bytes32 public testNode;
+ string public constant TEST_TEXT_KEY = "url";
+ string public constant TEST_TEXT_VALUE = "https://example.com";
+ uint256 public constant COIN_TYPE_ETH = 60;
+
+ // Storage slot constants (must match L1ConfigResolver)
+ uint256 constant SLOT_RECORD_VERSIONS = 0;
+ uint256 constant SLOT_VERSIONABLE_ADDRESSES = 2;
+ uint256 constant SLOT_VERSIONABLE_HASHES = 3;
+ uint256 constant SLOT_VERSIONABLE_TEXTS = 10;
+
+ function setUp() public {
+ // Use mainnet addresses for ENS (they're the same on all networks)
+ address ensRegistry = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e;
+ address nameWrapper = 0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401;
+
+ // Deploy ConfigResolver (L2) with mocked ENS
+ configResolver = new ConfigResolver(
+ ENS(ensRegistry),
+ INameWrapper(nameWrapper)
+ );
+
+ // Deploy mock verifier
+ mockVerifier = new MockGatewayVerifier();
+
+ // Deploy L1ConfigResolver (using Base chain ID 8453 for testing)
+ l1Resolver = new L1ConfigResolver(
+ IGatewayVerifier(address(mockVerifier)),
+ 8453,
+ address(configResolver)
+ );
+
+ // Set up test node (user's reverse node)
+ testNode = configResolver.reverseNode(user);
+
+ // Mock ENS to allow user to set records on their reverse node
+ vm.mockCall(
+ ensRegistry,
+ abi.encodeWithSelector(ENS.owner.selector, testNode),
+ abi.encode(user)
+ );
+
+ // Set up test data on ConfigResolver as user
+ vm.startPrank(user);
+ configResolver.setText(testNode, TEST_TEXT_KEY, TEST_TEXT_VALUE);
+ configResolver.setAddr(testNode, user);
+ configResolver.setContenthash(
+ testNode,
+ hex"e3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f"
+ );
+ vm.stopPrank();
+ }
+
+ // ============ Helper to call fetchCallback and get result ============
+
+ function _callFetchCallback(
+ bytes memory proof,
+ bytes memory carry
+ ) internal view returns (bytes memory) {
+ (bool success, bytes memory result) = address(l1Resolver).staticcall(
+ abi.encodeWithSelector(
+ l1Resolver.fetchCallback.selector,
+ proof,
+ carry
+ )
+ );
+ require(success, "fetchCallback failed");
+ return result;
+ }
+
+ // ============ Storage Slot Verification Tests ============
+
+ /// @notice Verify that SLOT_RECORD_VERSIONS is correct (slot 0)
+ function test_StorageSlot_RecordVersions() public view {
+ bytes32 slot = keccak256(abi.encode(testNode, uint256(0)));
+ uint256 version = uint256(vm.load(address(configResolver), slot));
+
+ // After setting records, version should still be 0 (only incremented by clearRecords)
+ assertEq(version, 0, "recordVersions should be at slot 0");
+ }
+
+ /// @notice Verify that SLOT_VERSIONABLE_ADDRESSES is correct (slot 2)
+ function test_StorageSlot_VersionableAddresses() public view {
+ // Storage layout: versionable_addresses[version][node][coinType]
+ // Slot calculation: keccak256(coinType, keccak256(node, keccak256(version, baseSlot)))
+ uint64 version = 0;
+ uint256 baseSlot = 2;
+
+ bytes32 slot1 = keccak256(abi.encode(version, baseSlot));
+ bytes32 slot2 = keccak256(abi.encode(testNode, slot1));
+ bytes32 slot3 = keccak256(abi.encode(COIN_TYPE_ETH, slot2));
+
+ // Read the stored value - for short bytes (<32), Solidity stores data|length in same slot
+ bytes32 storedValue = vm.load(address(configResolver), slot3);
+
+ // For 20-byte address, Solidity stores: [20 bytes of data][11 zero bytes][1 byte = 2*20 = 40]
+ // Extract the length from the lowest byte
+ uint8 encodedLength = uint8(uint256(storedValue) & 0xff);
+ // For short bytes, length is stored as 2*len, so actual length = encodedLength/2
+ assertEq(
+ encodedLength,
+ 40,
+ "Address bytes length encoding should be 2*20=40"
+ );
+
+ // Extract the address from high bytes
+ address storedAddr = address(uint160(uint256(storedValue) >> 96));
+ assertEq(storedAddr, user, "Stored address should match user");
+ }
+
+ /// @notice Verify that SLOT_VERSIONABLE_TEXTS is correct (slot 10)
+ function test_StorageSlot_VersionableTexts() public view {
+ // Storage layout: versionable_texts[version][node][key]
+ // For string keys in mappings, Solidity uses: keccak256(abi.encodePacked(key, slot))
+ uint64 version = 0;
+ uint256 baseSlot = 10;
+
+ bytes32 slot1 = keccak256(abi.encode(version, baseSlot));
+ bytes32 slot2 = keccak256(abi.encode(testNode, slot1));
+ // For string keys, use encodePacked(key, slot)
+ bytes32 slot3 = keccak256(abi.encodePacked(TEST_TEXT_KEY, slot2));
+
+ // Read the stored value
+ bytes32 storedValue = vm.load(address(configResolver), slot3);
+
+ // For short strings (<32 bytes), Solidity stores: [string data][padding][2*length]
+ // "https://example.com" is 19 bytes, so encoding = 2*19 = 38
+ uint8 encodedLength = uint8(uint256(storedValue) & 0xff);
+ assertEq(
+ encodedLength,
+ 38,
+ "Text record length encoding should be 2*19=38"
+ );
+ }
+
+ /// @notice Verify that SLOT_VERSIONABLE_HASHES is correct (slot 3)
+ function test_StorageSlot_VersionableHashes() public view {
+ // Storage layout: versionable_hashes[version][node]
+ uint64 version = 0;
+ uint256 baseSlot = 3;
+
+ bytes32 slot1 = keccak256(abi.encode(version, baseSlot));
+ bytes32 slot2 = keccak256(abi.encode(testNode, slot1));
+
+ // Read the stored contenthash length
+ uint256 storedLength = uint256(vm.load(address(configResolver), slot2));
+ // Our test contenthash is 38 bytes, stored as 2*38+1 = 77
+ assertEq(
+ storedLength,
+ 77,
+ "Contenthash length encoding should be correct"
+ );
+ }
+
+ // ============ Direct Read Tests (verify ConfigResolver data is set correctly) ============
+
+ function test_ConfigResolver_DirectRead_Text() public view {
+ string memory value = configResolver.text(testNode, TEST_TEXT_KEY);
+ assertEq(value, TEST_TEXT_VALUE, "Text record should be set correctly");
+ }
+
+ function test_ConfigResolver_DirectRead_Addr() public view {
+ address addr = configResolver.addr(testNode);
+ assertEq(addr, user, "Address record should be set correctly");
+ }
+
+ function test_ConfigResolver_DirectRead_Contenthash() public view {
+ bytes memory hash = configResolver.contenthash(testNode);
+ assertEq(
+ hash,
+ hex"e3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f",
+ "Contenthash should be set correctly"
+ );
+ }
+
+ // ============ CCIP-Read Flow Tests ============
+
+ /// @notice Test the full CCIP-Read flow for text() resolution
+ function test_CCIPRead_Text() public view {
+ // Simulate gateway response by reading directly from ConfigResolver
+ string memory expectedValue = configResolver.text(
+ testNode,
+ TEST_TEXT_KEY
+ );
+
+ // Prepare mock response
+ bytes[] memory values = new bytes[](1);
+ values[0] = bytes(expectedValue);
+ bytes memory proof = abi.encode(values, uint8(0));
+
+ // Build the carry data (Session struct)
+ GatewayRequest memory req = _buildTextRequest(testNode, TEST_TEXT_KEY);
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.textCallback.selector,
+ carry: ""
+ })
+ );
+
+ // Call fetchCallback
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ string memory result = abi.decode(resultBytes, (string));
+
+ assertEq(
+ result,
+ TEST_TEXT_VALUE,
+ "CCIP-Read text() should return correct value"
+ );
+ }
+
+ /// @notice Test the full CCIP-Read flow for addr() resolution
+ function test_CCIPRead_Addr() public view {
+ // Simulate gateway response
+ bytes memory expectedValue = abi.encodePacked(user);
+
+ bytes[] memory values = new bytes[](1);
+ values[0] = expectedValue;
+ bytes memory proof = abi.encode(values, uint8(0));
+
+ // Build carry data
+ GatewayRequest memory req = _buildAddrRequest(testNode, COIN_TYPE_ETH);
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.addrCallback.selector,
+ carry: abi.encode(testNode)
+ })
+ );
+
+ // Call fetchCallback
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ address result = abi.decode(resultBytes, (address));
+
+ assertEq(
+ result,
+ user,
+ "CCIP-Read addr() should return correct address"
+ );
+ }
+
+ /// @notice Test the full CCIP-Read flow for contenthash() resolution
+ function test_CCIPRead_Contenthash() public view {
+ // Simulate gateway response
+ bytes
+ memory expectedValue = hex"e3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f";
+
+ bytes[] memory values = new bytes[](1);
+ values[0] = expectedValue;
+ bytes memory proof = abi.encode(values, uint8(0));
+
+ // Build carry data
+ GatewayRequest memory req = _buildContenthashRequest(testNode);
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.contenthashCallback.selector,
+ carry: ""
+ })
+ );
+
+ // Call fetchCallback
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ bytes memory result = abi.decode(resultBytes, (bytes));
+
+ assertEq(
+ result,
+ expectedValue,
+ "CCIP-Read contenthash() should return correct value"
+ );
+ }
+
+ /// @notice Test resolve() with text selector
+ function test_CCIPRead_Resolve_Text() public view {
+ // Build the resolve calldata
+ bytes memory innerCalldata = abi.encodeWithSelector(
+ bytes4(0x59d1d43c),
+ testNode,
+ TEST_TEXT_KEY
+ );
+
+ // Simulate gateway response
+ string memory expectedValue = configResolver.text(
+ testNode,
+ TEST_TEXT_KEY
+ );
+ bytes[] memory values = new bytes[](1);
+ values[0] = bytes(expectedValue);
+ bytes memory proof = abi.encode(values, uint8(0));
+
+ // Build carry data
+ GatewayRequest memory req = _buildTextRequest(testNode, TEST_TEXT_KEY);
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.resolveCallback.selector,
+ carry: innerCalldata
+ })
+ );
+
+ // Call fetchCallback
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ string memory decodedResult = abi.decode(
+ abi.decode(resultBytes, (bytes)),
+ (string)
+ );
+
+ assertEq(
+ decodedResult,
+ TEST_TEXT_VALUE,
+ "resolve() with text selector should return correct value"
+ );
+ }
+
+ /// @notice Test resolve() with addr selector
+ function test_CCIPRead_Resolve_Addr() public view {
+ // Build the resolve calldata for addr(bytes32)
+ bytes memory innerCalldata = abi.encodeWithSelector(
+ bytes4(0x3b3b57de),
+ testNode
+ );
+
+ // Simulate gateway response
+ bytes[] memory values = new bytes[](1);
+ values[0] = abi.encodePacked(user);
+ bytes memory proof = abi.encode(values, uint8(0));
+
+ // Build carry data
+ GatewayRequest memory req = _buildAddrRequest(testNode, COIN_TYPE_ETH);
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.resolveCallback.selector,
+ carry: innerCalldata
+ })
+ );
+
+ // Call fetchCallback
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ address decodedResult = abi.decode(
+ abi.decode(resultBytes, (bytes)),
+ (address)
+ );
+
+ assertEq(
+ decodedResult,
+ user,
+ "resolve() with addr selector should return correct address"
+ );
+ }
+
+ // ============ Empty/Missing Record Tests ============
+
+ function test_CCIPRead_EmptyText() public view {
+ bytes32 emptyNode = keccak256("nonexistent");
+
+ bytes[] memory values = new bytes[](1);
+ values[0] = "";
+ bytes memory proof = abi.encode(values, uint8(0));
+
+ GatewayRequest memory req = _buildTextRequest(emptyNode, "nonexistent");
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.textCallback.selector,
+ carry: ""
+ })
+ );
+
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ string memory result = abi.decode(resultBytes, (string));
+ assertEq(result, "", "Empty text record should return empty string");
+ }
+
+ function test_CCIPRead_EmptyAddr() public view {
+ bytes[] memory values = new bytes[](1);
+ values[0] = "";
+ bytes memory proof = abi.encode(values, uint8(0));
+
+ GatewayRequest memory req = _buildAddrRequest(testNode, COIN_TYPE_ETH);
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.addrCallback.selector,
+ carry: ""
+ })
+ );
+
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ address result = abi.decode(resultBytes, (address));
+ assertEq(
+ result,
+ address(0),
+ "Empty address record should return zero address"
+ );
+ }
+
+ /// @notice Test exit code handling
+ function test_CCIPRead_ExitCode_NonZero() public view {
+ bytes[] memory values = new bytes[](1);
+ values[0] = "";
+ // Non-zero exit code indicates error/not found
+ bytes memory proof = abi.encode(values, uint8(1));
+
+ GatewayRequest memory req = _buildTextRequest(testNode, TEST_TEXT_KEY);
+ bytes memory carry = abi.encode(
+ GatewayFetchTarget.Session({
+ verifier: IGatewayVerifier(address(mockVerifier)),
+ context: mockVerifier.getLatestContext(),
+ req: req,
+ callback: L1ConfigResolver.textCallback.selector,
+ carry: ""
+ })
+ );
+
+ bytes memory resultBytes = _callFetchCallback(proof, carry);
+ string memory result = abi.decode(resultBytes, (string));
+ assertEq(
+ result,
+ "",
+ "Non-zero exit code should return empty string for text"
+ );
+ }
+
+ // ============ Interface Support Tests ============
+
+ function test_SupportsInterface_ERC165() public view {
+ assertTrue(
+ l1Resolver.supportsInterface(0x01ffc9a7),
+ "Should support ERC-165"
+ );
+ }
+
+ function test_SupportsInterface_ExtendedResolver() public view {
+ assertTrue(
+ l1Resolver.supportsInterface(0x9061b923),
+ "Should support IExtendedResolver"
+ );
+ }
+
+ function test_SupportsInterface_Addr() public view {
+ assertTrue(
+ l1Resolver.supportsInterface(0x3b3b57de),
+ "Should support addr(bytes32)"
+ );
+ }
+
+ function test_SupportsInterface_AddrMulti() public view {
+ assertTrue(
+ l1Resolver.supportsInterface(0xf1cb7e06),
+ "Should support addr(bytes32,uint256)"
+ );
+ }
+
+ function test_SupportsInterface_Text() public view {
+ assertTrue(
+ l1Resolver.supportsInterface(0x59d1d43c),
+ "Should support text(bytes32,string)"
+ );
+ }
+
+ function test_SupportsInterface_Contenthash() public view {
+ assertTrue(
+ l1Resolver.supportsInterface(0xbc1c58d1),
+ "Should support contenthash(bytes32)"
+ );
+ }
+
+ // ============ Immutable Getters Tests ============
+
+ function test_Verifier() public view {
+ assertEq(
+ address(l1Resolver.verifier()),
+ address(mockVerifier),
+ "Verifier should be set correctly"
+ );
+ }
+
+ function test_L2ConfigResolver() public view {
+ assertEq(
+ l1Resolver.l2ConfigResolver(),
+ address(configResolver),
+ "L2 ConfigResolver should be set correctly"
+ );
+ }
+
+ function test_L2ChainId() public view {
+ assertEq(
+ l1Resolver.l2ChainId(),
+ 8453,
+ "L2 Chain ID should be set correctly"
+ );
+ }
+
+ function test_SupportsInterface_IL1ConfigResolver() public view {
+ // IL1ConfigResolver interface ID
+ bytes4 interfaceId = type(IL1ConfigResolver).interfaceId;
+ assertTrue(
+ l1Resolver.supportsInterface(interfaceId),
+ "Should support IL1ConfigResolver"
+ );
+ }
+
+ // ============ Helper Functions ============
+
+ function _buildTextRequest(
+ bytes32 node,
+ string memory key
+ ) internal view returns (GatewayRequest memory req) {
+ req = GatewayFetcher.newRequest(1).setTarget(address(configResolver));
+ req = req.setSlot(SLOT_RECORD_VERSIONS).push(node).follow().read();
+ req = req.setSlot(SLOT_VERSIONABLE_TEXTS);
+ req = req.follow();
+ req = req.push(node).follow();
+ req = req.push(key).follow();
+ req = req.readBytes().setOutput(0);
+ }
+
+ function _buildAddrRequest(
+ bytes32 node,
+ uint256 coinType
+ ) internal view returns (GatewayRequest memory req) {
+ req = GatewayFetcher.newRequest(1).setTarget(address(configResolver));
+ req = req.setSlot(SLOT_RECORD_VERSIONS).push(node).follow().read();
+ req = req.setSlot(SLOT_VERSIONABLE_ADDRESSES);
+ req = req.follow();
+ req = req.push(node).follow();
+ req = req.push(coinType).follow();
+ req = req.readBytes().setOutput(0);
+ }
+
+ function _buildContenthashRequest(
+ bytes32 node
+ ) internal view returns (GatewayRequest memory req) {
+ req = GatewayFetcher.newRequest(1).setTarget(address(configResolver));
+ req = req.setSlot(SLOT_RECORD_VERSIONS).push(node).follow().read();
+ req = req.setSlot(SLOT_VERSIONABLE_HASHES);
+ req = req.follow();
+ req = req.push(node).follow();
+ req = req.readBytes().setOutput(0);
+ }
+}