Skip to content

Commit

Permalink
Merge pull request #205 from blockful-io/l2-writing
Browse files Browse the repository at this point in the history
L2 Subdomain Registering
  • Loading branch information
pikonha authored Oct 3, 2024
2 parents 9edddc4 + 4e52675 commit 62125e5
Show file tree
Hide file tree
Showing 36 changed files with 1,206 additions and 1,810 deletions.
18 changes: 9 additions & 9 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Common
RPC_URL=http://127.0.0.1:8545
REGISTRAR_ADDRESS=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 # Base Registrar
REGISTRY_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3 # ENS Registrar
UNIVERSAL_RESOLVER_ADDRESS=0x1fA02b2d6A771842690194Cf62D91bdd92BfE28d # UNiversal Resolver
GATEWAY_URL=http://127.0.0.1:3000/{sender}/{data}.json
DATABASE_URL=postgresql://blockful:ensdomains@localhost:5432/ensdomains
ETHERSCAN_API_KEY=DNXJA8RX2Q3VZ4URQIWP7Z68CJXQZSC6AW
# Base Registrar Implementation
REGISTRAR_ADDRESS=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 # local deployment
# ENS Registrar Implementation
REGISTRY_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3 # local deployment

# Database
CHAIN_ID=31337
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
GRAPHQL_URL=https://localhost:3000
DATABASE_URL=postgresql://blockful:ensdomains@localhost:5432/ensdomains

# Arbitrum
PRIVATE_KEY=0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659
LAYER2_RPC=http://127.0.0.1:8547
L2_REGISTRAR_ADDRESS=0xB66Ff14A830D5527f06e384B309288B843d555C4 # Subdomain registrar
L2_RESOLVER_ADDRESS=0xac3B14CB55C2242BB8Ca1dC8269701948CB0c348 # L2 Resolver
ROLLUP_ADDRESS=0x3cf538A94538a25ee3bcA0287aB530ACCf9Dbaf6 # L2 Rollup

# Metadata
METADATA_URL=https://localhost:3000
RESOLVER_ADDRESS=0x0165878A594ca255338adfa4d48449f69242Eb8F # local deployment
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ npm run migration:generate -- -n <migration_name>
npm run contracts dev:arb:l2
```
2. Gather the contract address from the terminal and add it [here](https://github.com/blockful-io/external-resolver/blob/main/packages/contracts/script/local/ArbResolver.s.sol#L56) so the L1 domain gets resolved by the L2 contract you just deployed.
2. Gather the contract address from the terminal and add it [here](https://github.com/blockful-io/external-resolver/blob/main/packages/contracts/script/local/L1ArbitrumResolver.s.sol#L56) so the L1 domain gets resolved by the L2 contract you just deployed.
3. Start the gateway:
Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@blockful/client",
"scripts": {
"test": "npm-run-all test:**",
"test:l1": "hardhat test ./test/l1.e2e.spec.ts --network localhost",
"test:l1": "hardhat test ./test/arb.e2e.spec.ts --network localhost",
"test:db": "hardhat test ./test/db.e2e.spec.ts --network localhost",
"start:read": "ts-node src/read.ts --resolver 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
"start:write:db": "ts-node src/db.write.ts --resolver 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
Expand Down
58 changes: 22 additions & 36 deletions packages/client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@ import {
RawContractError,
Hex,
Address,
Abi,
createPublicClient,
PrivateKeyAccount,
walletActions,
http,
Account,
defineChain,
} from 'viem'
import * as chains from 'viem/chains'

Expand All @@ -18,6 +14,10 @@ import {
TypedSignature,
} from '@blockful/gateway/src/types'

export interface RegisterParams {
price: bigint
}

export function getRevertErrorData(err: unknown) {
if (!(err instanceof BaseError)) return undefined
const error = err.walk() as RawContractError
Expand All @@ -44,36 +44,6 @@ export async function ccipRequest({
})
}

export async function handleL2Storage({
chainId,
l2Url,
args,
}: {
chainId: bigint
l2Url: string
args: {
abi: Abi | unknown[]
address: Address
account: Account
functionName: string
args: unknown[]
}
}) {
const chain = getChain(Number(chainId))

const l2Client = createPublicClient({
chain,
transport: http(l2Url),
}).extend(walletActions)

try {
const { request } = await l2Client.simulateContract(args)
await l2Client.writeContract(request)
} catch (err) {
console.log('error while trying to make the request: ', { err })
}
}

export async function handleDBStorage({
domain,
url,
Expand Down Expand Up @@ -108,5 +78,21 @@ export async function handleDBStorage({
}

export function getChain(chainId: number) {
return Object.values(chains).find((chain) => chain.id === chainId)
return [
...Object.values(chains),
defineChain({
id: Number(chainId),
name: 'Arbitrum Local',
nativeCurrency: {
name: 'Arbitrum Sepolia Ether',
symbol: 'ETH',
decimals: 18,
},
rpcUrls: {
default: {
http: ['http://127.0.0.1:8547'],
},
},
}),
].find((chain) => chain.id === chainId)
}
169 changes: 74 additions & 95 deletions packages/client/src/l2.write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Hash,
Hex,
createPublicClient,
encodeFunctionData,
getChainContractAddress,
http,
namehash,
Expand All @@ -17,21 +18,20 @@ import {
import { normalize, packetToBytes } from 'viem/ens'
import { privateKeyToAccount } from 'viem/accounts'

import { abi as l1Abi } from '@blockful/contracts/out/L1Resolver.sol/L1Resolver.json'
import { abi as l2Abi } from '@blockful/contracts/out/L2Resolver.sol/L2Resolver.json'
import { abi as uAbi } from '@blockful/contracts/out/UniversalResolver.sol/UniversalResolver.json'
import { getRevertErrorData, handleL2Storage, getChain } from './client'
import { abi as l1Abi } from '@blockful/contracts/out/L1Resolver.sol/L1Resolver.json'
import { getRevertErrorData, getChain, RegisterParams } from './client'

config({
path: process.env.ENV_FILE || '../.env',
})

let {
UNIVERSAL_RESOLVER_ADDRESS: resolver,
L2_RESOLVER_ADDRESS: l2Resolver,
CHAIN_ID: chainId = '31337',
RPC_URL: provider = 'http://127.0.0.1:8545/',
LAYER2_RPC: providerL2 = 'http://127.0.0.1:8547',
L2_RESOLVER: l2resolver,
PRIVATE_KEY:
privateKey = '0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659', // local arbitrum PK
} = process.env
Expand All @@ -46,9 +46,12 @@ const client = createPublicClient({

// eslint-disable-next-line
const _ = (async () => {
if (!l2resolver) throw new Error('L2_RESOLVER is required')
if (!l2Resolver) {
throw new Error('L2_RESOLVER_ADDRESS is required')
}

const publicAddress = normalize('blockful.eth')
const publicAddress = normalize('lucas.arb.eth')
const node = namehash(publicAddress)
const signer = privateKeyToAccount(privateKey as Hex)

if (!resolver) {
Expand All @@ -65,111 +68,87 @@ const _ = (async () => {
args: [toHex(packetToBytes(publicAddress))],
})) as Hash[]

// REGISTER NEW DOMAIN
try {
const { request } = await client.simulateContract({
functionName: 'register',
abi: l1Abi,
args: [toHex(packetToBytes(publicAddress)), l2resolver],
address: resolverAddr,
account: signer,
})
await client.writeContract(request)
const name = extractLabelFromName(publicAddress)
const duration = 31556952000n

await client.simulateContract({
functionName: 'setOwner',
abi: l1Abi,
args: [toHex(packetToBytes(publicAddress)), signer.address],
address: resolverAddr,
})
} catch (err) {
const data = getRevertErrorData(err)
if (data?.errorName === 'StorageHandledByL2') {
const [chainId, contractAddress] = data.args as [bigint, `0x${string}`]
// SUBDOMAIN PRICING

await handleL2Storage({
chainId,
l2Url: providerL2,
args: {
functionName: 'setOwner',
abi: l2Abi,
args: [namehash(publicAddress), signer.address],
address: contractAddress,
account: signer,
},
})
} else if (data) {
console.error('error registering domain: ', data.errorName)
} else {
console.error('error registering domain: ', { err })
}
}
const registerParams = (await client.readContract({
address: resolverAddr,
abi: l1Abi,
functionName: 'registerParams',
args: [toHex(name), duration],
})) as RegisterParams

// SET TEXT
try {
await client.simulateContract({
// REGISTER NEW SUBDOMAIN

const data: Hex[] = [
encodeFunctionData({
functionName: 'setText',
abi: l1Abi,
args: [toHex(packetToBytes(publicAddress)), 'com.twitter', '@blockful'],
address: resolverAddr,
})
} catch (err) {
const data = getRevertErrorData(err)
if (data?.errorName === 'StorageHandledByL2') {
const [chainId, contractAddress] = data.args as [bigint, `0x${string}`]

await handleL2Storage({
chainId,
l2Url: providerL2,
args: {
functionName: 'setText',
abi: l2Abi,
args: [namehash(publicAddress), 'com.twitter', '@blockful'],
address: contractAddress,
account: signer,
},
})
} else if (data) {
console.error('error setting text: ', data.errorName)
} else {
console.error('error setting text: ', { err })
}
args: [node, 'com.twitter', '@lucas'],
}),
encodeFunctionData({
functionName: 'setAddr',
abi: l1Abi,
args: [node, '0x3a872f8FED4421E7d5BE5c98Ab5Ea0e0245169A0'],
}),
encodeFunctionData({
functionName: 'setAddr',
abi: l1Abi,
args: [node, 1n, '0x3a872f8FED4421E7d5BE5c98Ab5Ea0e0245169A0'],
}),
]

const calldata = {
functionName: 'register',
abi: l1Abi,
args: [
name,
signer.address, // owner
duration,
`0x${'a'.repeat(64)}` as Hex, // secret
l2Resolver, // resolver
data, // calldata
false, // primaryName
0, // fuses
],
address: resolverAddr,
account: signer,
value: registerParams.price,
}

// SET ADDRESS
try {
await client.simulateContract({
functionName: 'setAddr',
abi: l1Abi,
args: [
toHex(packetToBytes(publicAddress)),
'0x04270c4366010A52192bC8D3E29d9f0E21bBe969',
],
address: resolverAddr,
})
await client.simulateContract(calldata)
} catch (err) {
const data = getRevertErrorData(err)
if (data?.errorName === 'StorageHandledByL2') {
const [chainId, contractAddress] = data.args as [bigint, `0x${string}`]

await handleL2Storage({
chainId,
l2Url: providerL2,
args: {
functionName: 'setAddr',
abi: l2Abi,
args: [
namehash(publicAddress),
'0x04270c4366010A52192bC8D3E29d9f0E21bBe969',
],
const l2Client = createPublicClient({
chain: getChain(Number(chainId)),
transport: http(providerL2),
}).extend(walletActions)

try {
const { request } = await l2Client.simulateContract({
...calldata,
address: contractAddress,
account: signer,
},
})
})
await l2Client.writeContract(request)
} catch (err) {
console.log('error while trying to make the request: ', { err })
}
} else if (data) {
console.error('error setting addr: ', data.errorName)
console.error('error registering domain: ', data.errorName)
} else {
console.error('error setting addr: ', { err })
console.error('error registering domain: ', { err })
}
}
})()

// gather the first part of the domain (e.g. floripa.blockful.eth -> floripa)
function extractLabelFromName(name: string): string {
const [, label] = /^(\w+)/.exec(name) || []
return label
}
Loading

0 comments on commit 62125e5

Please sign in to comment.