From 86f081994ebe810c44f2bdbd31b7db7dd445fd7d Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 7 Nov 2024 17:01:49 +0700 Subject: [PATCH 1/8] feat: wildcard writing interface v0.2 --- packages/client/src/write.ts | 38 +++--- .../script/local/L2ArbitrumResolver.sol | 27 ++-- packages/contracts/src/DatabaseResolver.sol | 24 ++++ packages/contracts/src/L1Resolver.sol | 7 +- .../contracts/src/SubdomainController.sol | 52 ++++---- .../src/interfaces/WildcardWriting.sol | 121 ++++++++++-------- 6 files changed, 157 insertions(+), 112 deletions(-) diff --git a/packages/client/src/write.ts b/packages/client/src/write.ts index 40e1ad9..84effcf 100644 --- a/packages/client/src/write.ts +++ b/packages/client/src/write.ts @@ -93,15 +93,16 @@ const _ = (async () => { functionName: 'register', abi: scAbi, args: [ - encodedName, - signer.address, // owner - duration, - zeroHash, - resolver, - data, // records calldata - false, // reverseRecord - 0, // fuses - zeroHash, + { + name: encodedName, + owner: signer.address, + duration, + resolver, + data, + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], account: signer, } @@ -154,13 +155,18 @@ const _ = (async () => { let value = 0n try { - const [_value /* commitTime */ /* extraData */, ,] = - (await client.readContract({ - address: contractAddress, - abi: scAbi, - functionName: 'registerParams', - args: [encodedName, duration], - })) as [bigint, bigint, Hex] + const { price: _value } = (await client.readContract({ + address: contractAddress, + abi: scAbi, + functionName: 'registerParams', + args: [encodedName, duration], + })) as { + price: bigint + commitTime: bigint + extraData: Hex + available: boolean + token: Hex + } value = _value } catch { // interface not implemented by the resolver diff --git a/packages/contracts/script/local/L2ArbitrumResolver.sol b/packages/contracts/script/local/L2ArbitrumResolver.sol index 0323e02..9128950 100644 --- a/packages/contracts/script/local/L2ArbitrumResolver.sol +++ b/packages/contracts/script/local/L2ArbitrumResolver.sol @@ -25,6 +25,7 @@ import {NameEncoder} from "@ens-contracts/utils/NameEncoder.sol"; import {ENSHelper} from "../ENSHelper.sol"; import {SubdomainController} from "../../src/SubdomainController.sol"; +import {OffchainRegister} from "../../src/interfaces/OffchainResolver.sol"; contract L2ArbitrumResolver is Script, ENSHelper { @@ -80,10 +81,8 @@ contract L2ArbitrumResolver is Script, ENSHelper { nameWrapper.setController(msg.sender, true); uint256 subdomainPrice = 0.001 ether; - uint256 commitTime = 0; - SubdomainController subdomainController = new SubdomainController( - address(nameWrapper), subdomainPrice, commitTime - ); + SubdomainController subdomainController = + new SubdomainController(address(nameWrapper), subdomainPrice); nameWrapper.setApprovalForAll(address(subdomainController), true); PublicResolver arbResolver = new PublicResolver( @@ -109,21 +108,23 @@ contract L2ArbitrumResolver is Script, ENSHelper { ); subdomainController.register{value: subdomainController.price()}( - name, - msg.sender, - 31556952000, - keccak256("secret"), - address(arbResolver), - data, - false, - 0, - bytes("") + OffchainRegister.RegisterRequest( + name, + msg.sender, + 31556952000, + address(arbResolver), + data, + false, + 0, + bytes("") + ) ); vm.stopBroadcast(); console.log("Registry deployed at", address(registry)); console.log("NameWrapper deployed at", address(nameWrapper)); + console.log("BaseRegistrar deployed at", address(baseRegistrar)); console.log( "SubdomainController deployed at", address(subdomainController) ); diff --git a/packages/contracts/src/DatabaseResolver.sol b/packages/contracts/src/DatabaseResolver.sol index c84b5eb..7e7c51e 100644 --- a/packages/contracts/src/DatabaseResolver.sol +++ b/packages/contracts/src/DatabaseResolver.sol @@ -10,6 +10,7 @@ import {IExtendedResolver} from import {AddrResolver} from "@ens-contracts/resolvers/profiles/AddrResolver.sol"; import {NameResolver} from "@ens-contracts/resolvers/profiles/NameResolver.sol"; import {ABIResolver} from "@ens-contracts/resolvers/profiles/ABIResolver.sol"; +import {IMulticallable} from "@ens-contracts/resolvers/IMulticallable.sol"; import {PubkeyResolver} from "@ens-contracts/resolvers/profiles/PubkeyResolver.sol"; import {TextResolver} from "@ens-contracts/resolvers/profiles/TextResolver.sol"; @@ -402,6 +403,29 @@ contract DatabaseResolver is return result; } + //////// MULTICALL //////// + + function multicall(bytes[] calldata /* data */ ) + external + view + override + returns (bytes[] memory) + { + _offChainStorage(); + } + + function multicallWithNodeCheck( + bytes32, /* node */ + bytes[] calldata /* data */ + ) + external + view + override + returns (bytes[] memory) + { + _offChainStorage(); + } + //////// ENS WRITE DEFERRAL RESOLVER (EIP-5559) //////// /** diff --git a/packages/contracts/src/L1Resolver.sol b/packages/contracts/src/L1Resolver.sol index 0c8dfd4..4b9ce52 100644 --- a/packages/contracts/src/L1Resolver.sol +++ b/packages/contracts/src/L1Resolver.sol @@ -8,6 +8,7 @@ import {IAddrResolver} from "@ens-contracts/resolvers/profiles/IAddrResolver.sol"; import {IAddressResolver} from "@ens-contracts/resolvers/profiles/IAddressResolver.sol"; +import {IMulticallable} from "@ens-contracts/resolvers/IMulticallable.sol"; import {AddrResolver} from "@ens-contracts/resolvers/profiles/AddrResolver.sol"; import {TextResolver} from "@ens-contracts/resolvers/profiles/TextResolver.sol"; import {ContentHashResolver} from @@ -20,9 +21,7 @@ import {EVMFetcher} from "./evmgateway/EVMFetcher.sol"; import {IEVMVerifier} from "./evmgateway/IEVMVerifier.sol"; import {EVMFetchTarget} from "./evmgateway/EVMFetchTarget.sol"; import {IWriteDeferral} from "./interfaces/IWriteDeferral.sol"; -import { - WildcardWriting, OffchainRegister -} from "./interfaces/WildcardWriting.sol"; +import {WildcardWriting} from "./interfaces/WildcardWriting.sol"; contract L1Resolver is EVMFetchTarget, @@ -64,8 +63,6 @@ contract L1Resolver is uint256 constant VERSIONABLE_HASHES_SLOT = 3; uint256 constant VERSIONABLE_TEXTS_SLOT = 10; uint256 constant PRICE_SLOT = 0; - uint256 constant COMMIT_SLOT = 1; - uint256 constant EXTRA_DATA_SLOT = 2; /// Contract targets bytes32 public constant TARGET_RESOLVER = keccak256("resolver"); diff --git a/packages/contracts/src/SubdomainController.sol b/packages/contracts/src/SubdomainController.sol index 398e562..1bf0657 100644 --- a/packages/contracts/src/SubdomainController.sol +++ b/packages/contracts/src/SubdomainController.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.17; import {INameWrapper} from "@ens-contracts/wrapper/INameWrapper.sol"; +import {ENSRegistry} from "@ens-contracts/registry/ENSRegistry.sol"; import {Resolver} from "@ens-contracts/resolvers/Resolver.sol"; import {BytesUtils} from "@ens-contracts/utils/BytesUtils.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; @@ -9,7 +10,8 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {ENSHelper} from "../script/ENSHelper.sol"; import { OffchainRegister, - OffchainRegisterParams + OffchainRegisterParams, + RegisterRequest } from "./interfaces/WildcardWriting.sol"; contract SubdomainController is @@ -22,45 +24,37 @@ contract SubdomainController is using BytesUtils for bytes; uint256 public price; - uint256 public commitTime; INameWrapper nameWrapper; - constructor( - address _nameWrapperAddress, - uint256 _price, - uint256 _commitTime - ) { - commitTime = _commitTime; + constructor(address _nameWrapperAddress, uint256 _price) { price = _price; nameWrapper = INameWrapper(_nameWrapperAddress); } function registerParams( - bytes calldata, /* name */ + bytes calldata name, uint256 /* duration */ ) external view - returns (uint256, uint256, bytes memory) + override + returns (RegisterParams memory) { - return (price, commitTime, ""); + return RegisterParams({ + price: price, + available: nameWrapper.ownerOf(uint256(name.namehash(0))) == address(0), + token: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, // EIP-7528 ETH + commitTime: 0, + extraData: "" + }); } - function register( - bytes calldata name, - address owner, - uint256 duration, - bytes32, /* secret */ - address resolver, - bytes[] calldata data, - bool, /* reverseRecord */ - uint16 fuses, - bytes memory /* extraData */ - ) + function register(RegisterRequest calldata request) external payable override { + bytes calldata name = request.name; bytes32 node = name.namehash(0); string memory label = _getLabel(name); @@ -74,11 +68,19 @@ contract SubdomainController is require(msg.value >= price, "insufficient funds"); nameWrapper.setSubnodeRecord( - parentNode, label, owner, resolver, 0, fuses, uint64(duration) + parentNode, + label, + request.owner, + request.resolver, + 0, + request.fuses, + uint64(request.duration) ); - if (data.length > 0) { - Resolver(resolver).multicallWithNodeCheck(node, data); + if (request.data.length > 0) { + Resolver(request.resolver).multicallWithNodeCheck( + node, request.data + ); } } diff --git a/packages/contracts/src/interfaces/WildcardWriting.sol b/packages/contracts/src/interfaces/WildcardWriting.sol index a2f15c7..d836295 100644 --- a/packages/contracts/src/interfaces/WildcardWriting.sol +++ b/packages/contracts/src/interfaces/WildcardWriting.sol @@ -16,81 +16,96 @@ interface WildcardWriting { } +/// @notice The details of a registration request. +/// @param name The DNS-encoded name being registered (e.g. "alice.eth", "alice.bob.eth") +/// @param owner The address that will own the registered name +/// @param duration The length of time in seconds to register the name for +/// @param secret The secret to be used for the registration based on commit/reveal +/// @param resolver The address of the resolver contract that will store the name's records +/// @param data Array of encoded function calls to set records in the resolver after registration +/// @param reverseRecord Whether to set this name as the primary name for the owner address +/// @param fuses Permissions to set on the name that control how it can be managed +/// @param extraData Additional registration data encoded as bytes +struct RegisterRequest { + bytes name; + address owner; + uint256 duration; + bytes32 secret; + address resolver; + bytes[] data; + bool reverseRecord; + uint16 fuses; + bytes extraData; +} + interface OffchainRegister { - /** - * Forwards the registering of a domain to the L2 contracts - * @param name DNS-encoded name to be registered. - * @param owner Owner of the domain - * @param duration duration The duration in seconds of the registration. - * @param secret The secret to be used for the registration based on commit/reveal - * @param resolver The address of the resolver to set for this name. - * @param data Multicallable data bytes for setting records in the associated resolver upon reigstration. - * @param reverseRecord Whether this name is the primary name - * @param fuses The fuses to set for this name. - * @param extraData any encoded additional data - */ - function register( - bytes calldata name, - address owner, - uint256 duration, - bytes32 secret, - address resolver, - bytes[] calldata data, - bool reverseRecord, - uint16 fuses, - bytes memory extraData - ) - external - payable; + /// @notice Registers a domain name + /// @param request The registration request details + /// @dev Forwards the registration request to the L2 contracts for processing + function register(RegisterRequest calldata request) external payable; } interface OffchainRegisterParams { - /** - * @notice Returns the registration parameters for a given name and duration - * @param name The DNS-encoded name to query - * @param duration The duration in seconds for the registration - * @return price The price of the registration in wei per second - * @return commitTime the amount of time the commit should wait before being revealed - * @return extraData any given structure in an ABI encoded format - */ + /// @notice Struct containing registration parameters for a name + /// @param price The total price in wei required to register the name + /// @param available Whether the name is available for registration + /// @param token Token address (ERC-7528 ether address or ERC-20 contract) + /// @param commitTime The commit duration in seconds + /// @param extraData Additional registration data encoded as bytes + struct RegisterParams { + uint256 price; + bool available; + address token; + uint256 commitTime; + bytes extraData; + } + + /// @notice Returns the registration parameters for a given name and duration + /// @dev This function calculates and returns the registration parameters needed to register a name + /// @param name The DNS-encoded name to query for registration parameters (e.g. "alice.eth", "alice.bob.eth") + /// @param duration The duration in seconds for which the name should be registered + /// @return A struct containing the registration parameters function registerParams( bytes calldata name, uint256 duration ) external view - returns (uint256 price, uint256 commitTime, bytes memory extraData); + returns (RegisterParams memory); } interface OffchainCommitable { - /** - * @notice produces the commit hash from the register calldata - * @return commitHash the hash of the commit to be used - */ - function makeCommitment( - string calldata name, - address owner, - uint256 duration, - bytes32 secret, - address resolver, - bytes[] calldata data, - bool reverseRecord, - uint16 fuses, - bytes memory extraData - ) + /// @notice Produces the commit hash from the register request + /// @param request The registration request details + /// @return commitHash The hash that should be committed before registration + function makeCommitment(RegisterRequest calldata request) external pure returns (bytes32 commitHash); - /** - * @notice Commits the register callData to prevent frontrunning. - * @param commitment hash of the register callData - */ + /// @notice Commits a hash of registration data to prevent frontrunning + /// @param commitment The hash of the registration request data that will be used in a future register call + /// @dev The commitment must be revealed after the minimum commit age and before the maximum commit age function commit(bytes32 commitment) external; } + +interface OffchainTransferrable { + + /// @notice Transfers ownership of a name to a new address + /// @param name The DNS-encoded name to transfer (e.g. "alice.eth", "alice.bob.eth") + /// @param owner The current owner of the name + /// @param newOwner The address to transfer ownership to + function transferFrom( + bytes calldata name, + address owner, + address newOwner + ) + external; + +} From 99f28e186f97e4472a82e19418c6e741265bf4c8 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 7 Nov 2024 19:23:48 +0700 Subject: [PATCH 2/8] fix: add RegisterRequest import --- packages/contracts/script/local/L2ArbitrumResolver.sol | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/contracts/script/local/L2ArbitrumResolver.sol b/packages/contracts/script/local/L2ArbitrumResolver.sol index 9128950..c92935c 100644 --- a/packages/contracts/script/local/L2ArbitrumResolver.sol +++ b/packages/contracts/script/local/L2ArbitrumResolver.sol @@ -25,7 +25,10 @@ import {NameEncoder} from "@ens-contracts/utils/NameEncoder.sol"; import {ENSHelper} from "../ENSHelper.sol"; import {SubdomainController} from "../../src/SubdomainController.sol"; -import {OffchainRegister} from "../../src/interfaces/OffchainResolver.sol"; +import { + OffchainRegister, + RegisterRequest +} from "../../src/interfaces/OffchainResolver.sol"; contract L2ArbitrumResolver is Script, ENSHelper { @@ -108,10 +111,11 @@ contract L2ArbitrumResolver is Script, ENSHelper { ); subdomainController.register{value: subdomainController.price()}( - OffchainRegister.RegisterRequest( + RegisterRequest( name, msg.sender, 31556952000, + keccak256(abi.encode("secret")), address(arbResolver), data, false, From 925d62bb0729c8df669fe3c6bb66ee9000699e32 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 7 Nov 2024 19:49:12 +0700 Subject: [PATCH 3/8] fix: update client write --- package-lock.json | 276 +++++++++++++++++++++++++++++------ packages/client/package.json | 6 +- packages/client/src/write.ts | 2 + 3 files changed, 236 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec2105b..9c5b0f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -133,9 +133,9 @@ } }, "node_modules/@apollo/server": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.11.0.tgz", - "integrity": "sha512-SWDvbbs0wl2zYhKG6aGLxwTJ72xpqp0awb2lotNpfezd9VcAvzaUizzKQqocephin2uMoaA8MguoyBmgtPzNWw==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.11.2.tgz", + "integrity": "sha512-WUTHY7DDek8xAMn4Woa9Bl8duQUDzRYQkosX/d1DtCsBWESZyApR7ndnI5d6+W4KSTtqBHhJFkusEI7CWuIJXg==", "license": "MIT", "dependencies": { "@apollo/cache-control-types": "^1.0.3", @@ -154,7 +154,7 @@ "@types/node-fetch": "^2.6.1", "async-retry": "^1.2.1", "cors": "^2.8.5", - "express": "^4.17.1", + "express": "^4.21.1", "loglevel": "^1.6.8", "lru-cache": "^7.10.1", "negotiator": "^0.6.3", @@ -184,6 +184,117 @@ "graphql": "14.x || 15.x || 16.x" } }, + "node_modules/@apollo/server/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@apollo/server/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@apollo/server/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@apollo/server/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@apollo/server/node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/@apollo/server/node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/@apollo/server/node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -192,6 +303,81 @@ "node": ">=12" } }, + "node_modules/@apollo/server/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@apollo/server/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/@apollo/server/node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" + }, + "node_modules/@apollo/server/node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@apollo/server/node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@apollo/server/node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@apollo/server/node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/@apollo/server/node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", @@ -4418,28 +4604,28 @@ } }, "node_modules/@nomicfoundation/edr": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.6.3.tgz", - "integrity": "sha512-hThe5ORR75WFYTXKL0K2AyLDxkTMrG+VQ1yL9BhQYsuh3OIH+3yNDxMz2LjfvrpOrMmJ4kk5NKdFewpqDojjXQ==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.6.4.tgz", + "integrity": "sha512-YgrSuT3yo5ZQkbvBGqQ7hG+RDvz3YygSkddg4tb1Z0Y6pLXFzwrcEwWaJCFAVeeZxdxGfCgGMUYgRVneK+WXkw==", "dev": true, "license": "MIT", "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.6.3", - "@nomicfoundation/edr-darwin-x64": "0.6.3", - "@nomicfoundation/edr-linux-arm64-gnu": "0.6.3", - "@nomicfoundation/edr-linux-arm64-musl": "0.6.3", - "@nomicfoundation/edr-linux-x64-gnu": "0.6.3", - "@nomicfoundation/edr-linux-x64-musl": "0.6.3", - "@nomicfoundation/edr-win32-x64-msvc": "0.6.3" + "@nomicfoundation/edr-darwin-arm64": "0.6.4", + "@nomicfoundation/edr-darwin-x64": "0.6.4", + "@nomicfoundation/edr-linux-arm64-gnu": "0.6.4", + "@nomicfoundation/edr-linux-arm64-musl": "0.6.4", + "@nomicfoundation/edr-linux-x64-gnu": "0.6.4", + "@nomicfoundation/edr-linux-x64-musl": "0.6.4", + "@nomicfoundation/edr-win32-x64-msvc": "0.6.4" }, "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.3.tgz", - "integrity": "sha512-hqtI7tYDqKG5PDmZ//Z65EH5cgH8VL/SAAu50rpHP7WAVfJWkOCcYbecywwF6nhHdonJbRTDGAeG1/+VOy6zew==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.4.tgz", + "integrity": "sha512-QNQErISLgssV9+qia8sIjRANqtbW8snSDvjspixT/kSQ5ZSGxxctTg7x72wPSrcu8+EBEveIe5uqENIp5GH8HQ==", "dev": true, "license": "MIT", "engines": { @@ -4447,9 +4633,9 @@ } }, "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.3.tgz", - "integrity": "sha512-4fGi79/lyOlRUORhCYsYb3sWqRHuHT7qqzyZfZuNOn8llaxmT1k36xNmvpyg37R8SzjnhT/DzoukSJrs23Ip9Q==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.4.tgz", + "integrity": "sha512-cjVmREiwByyc9+oGfvAh49IAw+oVJHF9WWYRD+Tm/ZlSpnEVWxrGNBak2bd/JSYjn+mZE7gmWS4SMRi4nKaLUg==", "dev": true, "license": "MIT", "engines": { @@ -4457,9 +4643,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.3.tgz", - "integrity": "sha512-yFFTvGFMhfAvQ1Z2itUh1jpoUA+mVROyVELcaxjIq8fyg602lQmbS+NXkhQ+oaeDgJ+06mSENrHBg4fcfRf9cw==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.4.tgz", + "integrity": "sha512-96o9kRIVD6W5VkgKvUOGpWyUGInVQ5BRlME2Fa36YoNsRQMaKtmYJEU0ACosYES6ZTpYC8U5sjMulvPtVoEfOA==", "dev": true, "license": "MIT", "engines": { @@ -4467,9 +4653,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.3.tgz", - "integrity": "sha512-pOKmd0Fa3a6BHg5qbjbl/jMRELVi9oazbfiuU7Bvgn/dpTK+ID3jwT0SXiuC2zxjmPByWgXL6G9XRf5BPAM2rQ==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.4.tgz", + "integrity": "sha512-+JVEW9e5plHrUfQlSgkEj/UONrIU6rADTEk+Yp9pbe+mzNkJdfJYhs5JYiLQRP4OjxH4QOrXI97bKU6FcEbt5Q==", "dev": true, "license": "MIT", "engines": { @@ -4477,9 +4663,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.3.tgz", - "integrity": "sha512-3AUferhkLIXtLV63w5GjpHttzdxZ36i656XMy+pkBZbbiqnzIVeKWg6DJv1A94fQY16gB4gqj9CLq4CWvbNN6w==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.4.tgz", + "integrity": "sha512-nzYWW+fO3EZItOeP4CrdMgDXfaGBIBkKg0Y/7ySpUxLqzut40O4Mb0/+quqLAFkacUSWMlFp8nsmypJfOH5zoA==", "dev": true, "license": "MIT", "engines": { @@ -4487,9 +4673,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.3.tgz", - "integrity": "sha512-fr6bD872WIBXe9YnTDi0CzYepMcYRgSnkVqn0yK4wRnIvKrloWhxXNVY45GVIl51aNZguBnvoA4WEt6HIazs3A==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.4.tgz", + "integrity": "sha512-QFRoE9qSQ2boRrVeQ1HdzU+XN7NUgwZ1SIy5DQt4d7jCP+5qTNsq8LBNcqhRBOATgO63nsweNUhxX/Suj5r1Sw==", "dev": true, "license": "MIT", "engines": { @@ -4497,9 +4683,9 @@ } }, "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.3.tgz", - "integrity": "sha512-sn34MvN1ajw2Oq1+Drpxej78Z0HfIzI4p4WlolupAV9dOZKzp2JAIQeLVfZpjIFbF3zuyxLPP4dUBrQoFPEqhA==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.4.tgz", + "integrity": "sha512-2yopjelNkkCvIjUgBGhrn153IBPLwnsDeNiq6oA0WkeM8tGmQi4td+PGi9jAriUDAkc59Yoi2q9hYA6efiY7Zw==", "dev": true, "license": "MIT", "engines": { @@ -14091,15 +14277,15 @@ } }, "node_modules/hardhat": { - "version": "2.22.12", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.12.tgz", - "integrity": "sha512-yok65M+LsOeTBHQsjg//QreGCyrsaNmeLVzhTFqlOvZ4ZE5y69N0wRxH1b2BC9dGK8S8OPUJMNiL9X0RAvbm8w==", + "version": "2.22.15", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.15.tgz", + "integrity": "sha512-BpTGa9PE/sKAaHi4s/S1e9WGv63DR1m7Lzfd60C8gSEchDPfAJssVRSq0MZ2v2k76ig9m0kHAwVLf5teYwu/Mw==", "dev": true, "license": "MIT", "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.6.1", + "@nomicfoundation/edr": "^0.6.4", "@nomicfoundation/ethereumjs-common": "4.0.4", "@nomicfoundation/ethereumjs-tx": "5.0.4", "@nomicfoundation/ethereumjs-util": "9.0.4", @@ -23640,9 +23826,9 @@ } }, "node_modules/viem": { - "version": "2.21.19", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.21.19.tgz", - "integrity": "sha512-FdlkN+UI1IU5sYOmzvygkxsUNjDRD5YHht3gZFu2X9xFv6Z3h9pXq9ycrYQ3F17lNfb41O2Ot4/aqbUkwOv9dA==", + "version": "2.21.42", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.21.42.tgz", + "integrity": "sha512-PWBb3iaVFAzLWUaNrYLweOGwHPTQid5J4HfERh/WjJgixbAFwb4ZEc1leRfygvgJPtqUGdYNapvw9b2k2FoCAg==", "funding": [ { "type": "github", @@ -25652,7 +25838,7 @@ "packages/client": { "name": "@blockful/client", "devDependencies": { - "@apollo/server": "^4.11.0", + "@apollo/server": "^4.11.2", "@blockful/ccip-server": "*", "@blockful/gateway": "*", "@nomicfoundation/hardhat-toolbox": "^5.0.0", @@ -25664,12 +25850,12 @@ "aes-js": "^3.1.2", "chai": "^4.2.0", "dotenv": "^16.4.5", - "hardhat": "^2.22.12", + "hardhat": "^2.22.15", "npm-run-all": "^4.1.5", "reflect-metadata": "^0.2.2", "solidity-coverage": "^0.8.12", "typeorm": "^0.3.20", - "viem": "^2.21.19" + "viem": "^2.21.42" }, "peerDependencies": { "@blockful/tsconfig": "*" diff --git a/packages/client/package.json b/packages/client/package.json index c9ab9f5..99ce163 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -10,7 +10,7 @@ "lint": "eslint . --ext .ts --fix" }, "devDependencies": { - "@apollo/server": "^4.11.0", + "@apollo/server": "^4.11.2", "@blockful/ccip-server": "*", "@blockful/gateway": "*", "@nomicfoundation/hardhat-toolbox": "^5.0.0", @@ -22,12 +22,12 @@ "aes-js": "^3.1.2", "chai": "^4.2.0", "dotenv": "^16.4.5", - "hardhat": "^2.22.12", + "hardhat": "^2.22.15", "npm-run-all": "^4.1.5", "reflect-metadata": "^0.2.2", "solidity-coverage": "^0.8.12", "typeorm": "^0.3.20", - "viem": "^2.21.19" + "viem": "^2.21.42" }, "peerDependencies": { "@blockful/tsconfig": "*" diff --git a/packages/client/src/write.ts b/packages/client/src/write.ts index 84effcf..33e945a 100644 --- a/packages/client/src/write.ts +++ b/packages/client/src/write.ts @@ -5,6 +5,7 @@ import { config } from 'dotenv' import { + Address, Hex, createPublicClient, decodeErrorResult, @@ -97,6 +98,7 @@ const _ = (async () => { name: encodedName, owner: signer.address, duration, + secret: zeroHash, resolver, data, reverseRecord: false, From c32049e3cd06f44957b53c0459c53d2f0117a1e7 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Thu, 7 Nov 2024 20:23:46 +0700 Subject: [PATCH 4/8] fix: subdomain deploy and test --- .../script/deploy/SubdomainController.sol | 6 +- .../contracts/test/SubdomainController.t.sol | 84 ++++++++++--------- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/packages/contracts/script/deploy/SubdomainController.sol b/packages/contracts/script/deploy/SubdomainController.sol index 09ba590..c4086bd 100644 --- a/packages/contracts/script/deploy/SubdomainController.sol +++ b/packages/contracts/script/deploy/SubdomainController.sol @@ -18,10 +18,8 @@ contract SubdomainControllerScript is DeployHelper, ENSHelper { vm.startBroadcast(); uint256 subdomainPrice = 0.001 ether; - uint256 commitTime = 0; - SubdomainController subdomainController = new SubdomainController( - address(nameWrapper), subdomainPrice, commitTime - ); + SubdomainController subdomainController = + new SubdomainController(address(nameWrapper), subdomainPrice); nameWrapper.setApprovalForAll(address(subdomainController), true); vm.stopBroadcast(); diff --git a/packages/contracts/test/SubdomainController.t.sol b/packages/contracts/test/SubdomainController.t.sol index 91cd325..e836d33 100644 --- a/packages/contracts/test/SubdomainController.t.sol +++ b/packages/contracts/test/SubdomainController.t.sol @@ -82,13 +82,11 @@ contract SubdomainControllerTest is Test, ENSHelper { DummyResolver public resolver; uint256 constant PRICE = 0.1 ether; - uint256 constant COMMIT_TIME = 1 days; function setUp() public { nameWrapper = new DummyNameWrapper(); resolver = new DummyResolver(); - controller = - new SubdomainController(address(nameWrapper), PRICE, COMMIT_TIME); + controller = new SubdomainController(address(nameWrapper), PRICE); } function testRegister() public { @@ -115,15 +113,17 @@ contract SubdomainControllerTest is Test, ENSHelper { vm.deal(address(this), PRICE); controller.register{value: PRICE}( - name, - owner, - duration, - secret, - address(resolver), - data, - false, - 0, - abi.encode("") + RegisterRequest( + name, + owner, + duration, + secret, + address(resolver), + data, + false, + 0, + bytes("") + ) ); assertEq( @@ -144,15 +144,17 @@ contract SubdomainControllerTest is Test, ENSHelper { vm.expectRevert("insufficient funds"); controller.register{value: PRICE - 1}( - name, - owner, - duration, - secret, - address(resolver), - data, - false, - 0, - abi.encode("") + RegisterRequest( + name, + owner, + duration, + secret, + address(resolver), + data, + false, + 0, + bytes("") + ) ); } @@ -179,15 +181,17 @@ contract SubdomainControllerTest is Test, ENSHelper { vm.deal(address(this), PRICE); controller.register{value: PRICE}( - name, - owner, - duration, - secret, - address(resolver), - data, - false, - 0, - abi.encode("") + RegisterRequest( + name, + owner, + duration, + secret, + address(resolver), + data, + false, + 0, + bytes("") + ) ); } @@ -226,15 +230,17 @@ contract SubdomainControllerTest is Test, ENSHelper { vm.deal(address(this), PRICE); controller.register{value: PRICE}( - name, - owner, - duration, - secret, - address(resolver), - data, - false, - 0, - abi.encode("") + RegisterRequest( + name, + owner, + duration, + secret, + address(resolver), + data, + false, + 0, + bytes("") + ) ); assertEq( From c16f5f6cd1674c5388b06dd17ab036cc2266d74b Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Fri, 8 Nov 2024 12:36:25 +0700 Subject: [PATCH 5/8] test: db e2e register with struct --- packages/client/test/db.e2e.spec.ts | 100 +++++++++++++----------- packages/gateway/src/abi.ts | 2 +- packages/gateway/src/handlers/domain.ts | 4 +- 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/packages/client/test/db.e2e.spec.ts b/packages/client/test/db.e2e.spec.ts index bcec5a5..3a52e09 100644 --- a/packages/client/test/db.e2e.spec.ts +++ b/packages/client/test/db.e2e.spec.ts @@ -192,15 +192,17 @@ describe('DatabaseResolver', async () => { functionName: 'register', abi: abiOffchainRegister, args: [ - encodedName, - owner.address, - 300n, - zeroHash, - resolver, - [], - false, - 0, - zeroHash, + { + name: encodedName, + owner: owner.address, + duration: 300n, + secret: zeroHash, + resolver, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], universalResolverAddress, signer: owner, @@ -238,15 +240,17 @@ describe('DatabaseResolver', async () => { functionName: 'register', abi: abiOffchainRegister, args: [ - encodedName, - owner.address, - 300n, - zeroHash, - resolver, - calldata, - false, - 0, - zeroHash, + { + name: encodedName, + owner: owner.address, + duration: 300n, + secret: zeroHash, + resolver, + data: calldata, + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], universalResolverAddress, signer: owner, @@ -289,15 +293,17 @@ describe('DatabaseResolver', async () => { functionName: 'register', abi: abiOffchainRegister, args: [ - encodedName, - owner.address, - 300n, - zeroHash, - resolver, - [], - false, - 0, - zeroHash, + { + name: encodedName, + owner: owner.address, + duration: 300n, + secret: zeroHash, + resolver, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], universalResolverAddress, signer: owner, @@ -321,15 +327,17 @@ describe('DatabaseResolver', async () => { functionName: 'register', abi: abiOffchainRegister, args: [ - encodedName, - newOwner.address, - 300n, - zeroHash, - resolver, - [], - false, - 0, - zeroHash, + { + name: encodedName, + owner: newOwner.address, + duration: 300n, + secret: zeroHash, + resolver, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], universalResolverAddress, signer: newOwner, @@ -362,15 +370,17 @@ describe('DatabaseResolver', async () => { functionName: 'register', abi: abiOffchainRegister, args: [ - encodedName, - newOwner, - 300n, - zeroHash, - resolver, - [], - false, - 0, - zeroHash, + { + name: encodedName, + owner: newOwner, + duration: 300n, + secret: zeroHash, + resolver, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], universalResolverAddress, signer: owner, diff --git a/packages/gateway/src/abi.ts b/packages/gateway/src/abi.ts index 6269917..4025a61 100644 --- a/packages/gateway/src/abi.ts +++ b/packages/gateway/src/abi.ts @@ -14,7 +14,7 @@ export const abi: string[] = [ 'function setPubkey(bytes32 node,bytes32 x, bytes32 y)', 'function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y)', 'function getStorageSlots(address addr, bytes32[] memory commands, bytes[] memory) external view returns(bytes memory witness)', - 'function register(bytes calldata name, address owner, uint256 duration, bytes32 secret, address resolver, bytes[] calldata data, bool reverseRecord, uint16 fuses, bytes memory extraData)', + 'function register((bytes name,address owner,uint256 duration,bytes32 secret,address resolver,bytes[] data,bool reverseRecord,uint16 fuses,bytes extraData))', 'function transfer(bytes32 node, address owner)', 'function multicall(bytes[] calldata data) external returns (bytes[] memory results)', ] diff --git a/packages/gateway/src/handlers/domain.ts b/packages/gateway/src/handlers/domain.ts index 9fed2fa..3331e8b 100644 --- a/packages/gateway/src/handlers/domain.ts +++ b/packages/gateway/src/handlers/domain.ts @@ -30,9 +30,9 @@ export function withRegisterDomain( repo: WriteRepository & ReadRepository, ): ccip.HandlerDescription { return { - type: 'register(bytes calldata name, address owner, uint256 duration, bytes32 secret, address resolver, bytes[] calldata data, bool reverseRecord, uint16 fuses, bytes memory extraData)', + type: 'register((bytes name,address owner,uint256 duration,bytes32 secret,address resolver,bytes[] data,bool reverseRecord,uint16 fuses,bytes extraData))', func: async ( - { name, duration: ttl, owner, data }, + [[name, owner, ttl, , , data]], { signature }: { signature: TypedSignature }, ) => { try { From 431766cb5a1b81fd4b01ae743ebe37b51844365e Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Mon, 9 Dec 2024 06:29:46 -0300 Subject: [PATCH 6/8] fix: import from wildcard writing interface --- .../script/local/L2ArbitrumResolver.sol | 2 +- packages/contracts/src/DatabaseResolver.sol | 25 ++----------------- packages/contracts/src/L1Resolver.sol | 4 ++- 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/packages/contracts/script/local/L2ArbitrumResolver.sol b/packages/contracts/script/local/L2ArbitrumResolver.sol index c92935c..7217b33 100644 --- a/packages/contracts/script/local/L2ArbitrumResolver.sol +++ b/packages/contracts/script/local/L2ArbitrumResolver.sol @@ -28,7 +28,7 @@ import {SubdomainController} from "../../src/SubdomainController.sol"; import { OffchainRegister, RegisterRequest -} from "../../src/interfaces/OffchainResolver.sol"; +} from "../../src/interfaces/WildcardWriting.sol"; contract L2ArbitrumResolver is Script, ENSHelper { diff --git a/packages/contracts/src/DatabaseResolver.sol b/packages/contracts/src/DatabaseResolver.sol index 7e7c51e..0229bf9 100644 --- a/packages/contracts/src/DatabaseResolver.sol +++ b/packages/contracts/src/DatabaseResolver.sol @@ -411,7 +411,7 @@ contract DatabaseResolver is override returns (bytes[] memory) { - _offChainStorage(); + _offChainStorage(msg.data); } function multicallWithNodeCheck( @@ -423,7 +423,7 @@ contract DatabaseResolver is override returns (bytes[] memory) { - _offChainStorage(); + _offChainStorage(msg.data); } //////// ENS WRITE DEFERRAL RESOLVER (EIP-5559) //////// @@ -586,25 +586,4 @@ contract DatabaseResolver is || super.supportsInterface(interfaceID); } - function multicall(bytes[] calldata /* data */ ) - external - view - override - returns (bytes[] memory) - { - _offChainStorage(msg.data); - } - - function multicallWithNodeCheck( - bytes32, - bytes[] calldata /* data */ - ) - external - view - override - returns (bytes[] memory) - { - _offChainStorage(msg.data); - } - } diff --git a/packages/contracts/src/L1Resolver.sol b/packages/contracts/src/L1Resolver.sol index 4b9ce52..67603a7 100644 --- a/packages/contracts/src/L1Resolver.sol +++ b/packages/contracts/src/L1Resolver.sol @@ -21,7 +21,9 @@ import {EVMFetcher} from "./evmgateway/EVMFetcher.sol"; import {IEVMVerifier} from "./evmgateway/IEVMVerifier.sol"; import {EVMFetchTarget} from "./evmgateway/EVMFetchTarget.sol"; import {IWriteDeferral} from "./interfaces/IWriteDeferral.sol"; -import {WildcardWriting} from "./interfaces/WildcardWriting.sol"; +import { + WildcardWriting, OffchainRegister +} from "./interfaces/WildcardWriting.sol"; contract L1Resolver is EVMFetchTarget, From a92036c8f9f07151f419bdc5585b28f1acf1796d Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Mon, 9 Dec 2024 10:36:39 -0300 Subject: [PATCH 7/8] test: register with struct as arg --- packages/gateway/src/repositories/memory.ts | 35 ++++-- packages/gateway/test/api.spec.ts | 118 ++++++++++++-------- packages/gateway/test/database.spec.ts | 60 +++++----- 3 files changed, 129 insertions(+), 84 deletions(-) diff --git a/packages/gateway/src/repositories/memory.ts b/packages/gateway/src/repositories/memory.ts index 28b659a..bdb29a1 100644 --- a/packages/gateway/src/repositories/memory.ts +++ b/packages/gateway/src/repositories/memory.ts @@ -72,6 +72,7 @@ export class InMemoryRepository { resolverVersion, addresses, texts, + contenthash, }: RegisterDomainProps) { this.domains.set(node, { name, @@ -106,6 +107,16 @@ export class InMemoryRepository { }) }) } + if (contenthash) { + this.contenthashes.set(node, { + domain: node, + contenthash: contenthash.contenthash, + resolver, + resolverVersion, + createdAt: new Date(), + updatedAt: new Date(), + }) + } } async transfer({ node, owner }: TransferDomainProps) { @@ -123,17 +134,19 @@ export class InMemoryRepository { node, includeRelations = false, }: GetDomainProps): Promise { - const dbNode = this.domains.get(node) - if (!dbNode) return null - if (!includeRelations) return dbNode + const domain = this.domains.get(node) + if (!domain) return null + if (!includeRelations) return domain const addresses = await this.getAddresses({ node }) const texts = await this.getTexts({ node }) + const contenthash = await this.getContentHashs({ node }) return { - ...dbNode, + ...domain, addresses, texts, + contenthash, } } @@ -168,11 +181,15 @@ export class InMemoryRepository { async getContentHash({ node }: NodeProps): Promise { const domain = this.domains.get(node) const contenthash = this.contenthashes.get(node) - if (contenthash) - return { - value: contenthash.contenthash, - ttl: domain?.ttl || '600', - } + if (!contenthash) return + return { + value: contenthash.contenthash, + ttl: domain?.ttl || '600', + } + } + + async getContentHashs({ node }: NodeProps): Promise { + return this.contenthashes.get(node) } async setAddr({ diff --git a/packages/gateway/test/api.spec.ts b/packages/gateway/test/api.spec.ts index 2651bf5..7616f57 100644 --- a/packages/gateway/test/api.spec.ts +++ b/packages/gateway/test/api.spec.ts @@ -113,21 +113,22 @@ describe('Gateway API', () => { texts: [], } - const args = [ - toHex(packetToBytes(domain.name)), - owner, - 300n, - zeroHash, - TEST_ADDRESS, - [], - false, - 0, - zeroHash, - ] const data = encodeFunctionData({ abi, functionName: 'register', - args, + args: [ + { + name: toHex(packetToBytes(domain.name)), + owner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, + ], }) const signature = await signData({ @@ -159,21 +160,22 @@ describe('Gateway API', () => { server.add(serverAbi, withRegisterDomain(repo)) const app = server.makeApp('/') - const args = [ - toHex(packetToBytes(domain.name)), - owner, - 300n, - zeroHash, - TEST_ADDRESS, - [], - false, - 0, - zeroHash, - ] const data = encodeFunctionData({ abi, functionName: 'register', - args, + args: [ + { + name: toHex(packetToBytes(domain.name)), + owner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, + ], }) const signature = await signData({ @@ -221,21 +223,22 @@ describe('Gateway API', () => { texts: [], } - const args = [ - toHex(packetToBytes(domain.name)), - newOwner, - 300n, - zeroHash, - TEST_ADDRESS, - [], - false, - 0, - zeroHash, - ] const data = encodeFunctionData({ abi, functionName: 'register', - args, + args: [ + { + name: toHex(packetToBytes(domain.name)), + owner: newOwner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, + ], }) const signature = await signData({ @@ -278,6 +281,13 @@ describe('Gateway API', () => { resolverVersion: '1', owner, ttl: '300', + contenthash: { + contenthash: + 'ipns://k51qzi5uqu5dgccx524mfjv7znyfsa6g013o6v4yvis9dxnrjbwojc62pt0450', + resolver: TEST_ADDRESS, + resolverVersion: '1', + domain: node, + }, addresses: [ { address: '0x3a872f8fed4421e7d5be5c98ab5ea0e0245169a0', @@ -325,22 +335,34 @@ describe('Gateway API', () => { '0x3a872f8fed4421e7d5be5c98ab5ea0e0245169a2', ], }), + encodeFunctionData({ + functionName: 'setContenthash', + abi, + args: [ + node, + stringToHex( + 'ipns://k51qzi5uqu5dgccx524mfjv7znyfsa6g013o6v4yvis9dxnrjbwojc62pt0450', + ), + ], + }), ] - const args = [ - toHex(packetToBytes(domain.name)), - owner, - 300n, - zeroHash, - TEST_ADDRESS, - calldata, - false, - 0, - zeroHash, - ] + const data = encodeFunctionData({ abi, functionName: 'register', - args, + args: [ + { + name: toHex(packetToBytes(domain.name)), + owner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: calldata, + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, + ], }) const signature = await signData({ diff --git a/packages/gateway/test/database.spec.ts b/packages/gateway/test/database.spec.ts index c464fc9..fb3c4ee 100644 --- a/packages/gateway/test/database.spec.ts +++ b/packages/gateway/test/database.spec.ts @@ -95,15 +95,17 @@ describe('Gateway Database', () => { method: 'register', pvtKey, args: [ - toHex(packetToBytes(name)), - owner, - 300n, - zeroHash, - TEST_ADDRESS, - [], - false, - 0, - zeroHash, + { + name: toHex(packetToBytes(name)), + owner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], }) @@ -140,15 +142,17 @@ describe('Gateway Database', () => { method: 'register', pvtKey, args: [ - toHex(packetToBytes(domain.name)), - owner, - 300n, - zeroHash, - TEST_ADDRESS, - [], - false, - 0, - zeroHash, + { + name: toHex(packetToBytes(domain.name)), + owner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: [], + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], }) @@ -193,15 +197,17 @@ describe('Gateway Database', () => { method: 'register', pvtKey, args: [ - toHex(packetToBytes(name)), - owner, - 300n, - zeroHash, - TEST_ADDRESS, - calldata, - false, - 0, - zeroHash, + { + name: toHex(packetToBytes(name)), + owner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: calldata, + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, ], }) From 088fc3cd0cf1aed38c0c6c1c151185ee270c8b12 Mon Sep 17 00:00:00 2001 From: lucas picollo Date: Mon, 9 Dec 2024 10:42:36 -0300 Subject: [PATCH 8/8] feat: validate domain on registering w/ records --- packages/gateway/src/handlers/domain.ts | 6 +-- packages/gateway/src/services/calldata.ts | 22 ++++++++- packages/gateway/test/database.spec.ts | 58 +++++++++++++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/packages/gateway/src/handlers/domain.ts b/packages/gateway/src/handlers/domain.ts index 3331e8b..a3537a6 100644 --- a/packages/gateway/src/handlers/domain.ts +++ b/packages/gateway/src/handlers/domain.ts @@ -44,9 +44,9 @@ export function withRegisterDomain( return { error: { message: 'Domain already exists', status: 400 } } } - const addresses = parseEncodedAddressCalls(data, signature) - const texts = parseEncodedTextCalls(data, signature) - const contenthash = parseEncodedContentHashCall(data, signature) + const addresses = parseEncodedAddressCalls(data, node, signature) + const texts = parseEncodedTextCalls(data, node, signature) + const contenthash = parseEncodedContentHashCall(data, node, signature) await repo.register({ name, diff --git a/packages/gateway/src/services/calldata.ts b/packages/gateway/src/services/calldata.ts index 7dd29bc..6d51127 100644 --- a/packages/gateway/src/services/calldata.ts +++ b/packages/gateway/src/services/calldata.ts @@ -4,7 +4,11 @@ import { abi } from '../abi' import { TypedSignature } from '../types' import { Text, Address, Contenthash } from '../entities' -export function parseEncodedTextCalls(data: Hex[], signature: TypedSignature) { +export function parseEncodedTextCalls( + data: Hex[], + node: Hex, + signature: TypedSignature, +) { const callData = data.map((d: Hex) => decodeFunctionData({ abi: parseAbi(abi), data: d }), ) @@ -13,6 +17,10 @@ export function parseEncodedTextCalls(data: Hex[], signature: TypedSignature) { .filter((d) => d.functionName === 'setText') .map(({ args }): Omit => { const [domain, key, value] = args as [Hex, string, string] + + if (domain !== node) + throw new Error('All records must have a matching namehash') + return { key, value, @@ -25,6 +33,7 @@ export function parseEncodedTextCalls(data: Hex[], signature: TypedSignature) { export function parseEncodedAddressCalls( data: Hex[], + node: Hex, signature: TypedSignature, ) { const callData = data.map((d: Hex) => @@ -36,6 +45,9 @@ export function parseEncodedAddressCalls( .map(({ args }): Omit => { if (args?.length !== 3) { const [domain, address] = args as [Hex, string] + if (domain !== node) + throw new Error('All records must have a matching namehash') + return { domain, address: address.toLowerCase(), @@ -45,6 +57,9 @@ export function parseEncodedAddressCalls( } } const [domain, coin, address] = args as [Hex, string, string] + if (domain !== node) + throw new Error('All records must have a matching namehash') + return { domain, address, @@ -57,6 +72,7 @@ export function parseEncodedAddressCalls( export function parseEncodedContentHashCall( data: Hex[], + node: Hex, signature: TypedSignature, ): Omit | undefined { const callData = data.map((d: Hex) => @@ -67,6 +83,10 @@ export function parseEncodedContentHashCall( .filter((d) => d.functionName === 'setContenthash') .map(({ args }): Omit => { const [domain, contenthash] = args as [Hex, Hex] + + if (domain !== node) + throw new Error('All records must have a matching namehash') + return { domain, contenthash: hexToString(contenthash), diff --git a/packages/gateway/test/database.spec.ts b/packages/gateway/test/database.spec.ts index fb3c4ee..1321ea5 100644 --- a/packages/gateway/test/database.spec.ts +++ b/packages/gateway/test/database.spec.ts @@ -240,6 +240,64 @@ describe('Gateway Database', () => { }) expect(actualAddressWithCoin).toBe(true) }) + + it('should block registering a domain with records from another domain', async () => { + const pvtKey = generatePrivateKey() + const owner = privateKeyToAddress(pvtKey) + const name = 'blockful.eth' + const server = new ccip.Server() + server.add(abi, withRegisterDomain(repo)) + + const anotherNode = namehash('another.eth') + + const calldata = [ + encodeFunctionData({ + abi: parseAbi(abi), + functionName: 'setText', + args: [anotherNode, 'com.twitter', '@blockful.eth'], + }), + encodeFunctionData({ + functionName: 'setAddr', + abi: parseAbi(abi), + args: [anotherNode, '0x3a872f8fed4421e7d5be5c98ab5ea0e0245169a0'], + }), + encodeFunctionData({ + functionName: 'setAddr', + abi: parseAbi(abi), + args: [ + anotherNode, + 1n, + '0x3a872f8fed4421e7d5be5c98ab5ea0e0245169a2', + ], + }), + ] + await doCall({ + server, + abi, + sender: TEST_ADDRESS, + method: 'register', + pvtKey, + args: [ + { + name: toHex(packetToBytes(name)), + owner, + duration: 300n, + secret: zeroHash, + resolver: TEST_ADDRESS, + data: calldata, + reverseRecord: false, + fuses: 0, + extraData: zeroHash, + }, + ], + }) + + const actual = await datasource.getRepository(Domain).existsBy({ + node: namehash(name), + owner, + }) + expect(actual).toBe(false) + }) }) describe('Transfer Domain', () => {