Giter Site home page Giter Site logo

blockful-io / external-resolver Goto Github PK

View Code? Open in Web Editor NEW
7.0 1.0 2.0 1.88 MB

This project aims to scale the Ethereum Name Service (ENS) by consolidating existing patterns and proofs of concept into a unified and production-ready codebase.

License: MIT License

TypeScript 73.98% Solidity 25.12% JavaScript 0.09% Dockerfile 0.82%
ens ethereum solidity optimism-l2 typeorm viem

external-resolver's Introduction

External Resolver

This project aims to scale the Ethereum Name Service (ENS) by reducing costs for users and increasing its usage. The strategy involves combining existing patterns such as ERC-3668, EIP-5559, ENSIP-10 and ENSIP-16, along with proof of concepts to develop a comprehensive reference codebase for the industry.

The primary objective of this project is to enhance the scalability of ENS while making it more cost-effective for users. By increasing its usability, we aim to foster broader adoption within the community.

Components

  • L1 Resolver: A contract that is responsible for redirecting the request to the specified external source, such as L2 protocols and an external database.
  • L2 Resolver Contract: L2 contract that is able to resolve ENS domains to its corresponding address, as well as fetch information such as Twitter handle and avatar image.
  • Gateway: An API capable of handling reading data from an external source following the flow specified by the EIP-5559.
  • Client: A module that is able to read ENS domain properties even when stored in external data sources.

Usage

To run this application locally, follow these steps:

  1. Clone this repository to your local machine.
  2. Copy the env.example to a .env file on the root directory
  3. Install dependencies by running:
yarn install
cd packages/contracts && forge install && cd -
  1. Start the development server:
yarn start
  1. Run tests:
docker-compose up -d # start local blockchain node
yarn test
  1. Access the contracts through http://localhost:8545

Conclusion

This project seeks to significantly enhance the scalability and usability of the Ethereum Name Service through the development of a comprehensive reference codebase. By combining existing patterns and best practices, we aim to lower costs for users and drive increased adoption within the industry. We welcome collaboration and feedback from the community as we progress towards our goals.

Contributing

We welcome contributions from the community to improve this frontend application. To contribute, please follow these guidelines:

  1. Fork the repository and create a new branch for your feature or bug fix.

  2. Make your changes and ensure they follow the project's coding conventions.

  3. Test your changes locally to ensure they work as expected.

  4. Create a pull request with a detailed description of your changes.

License

This project is licensed under the MIT License.

Acknowledgements

Special thanks to the Ethereum Name Service (ENS) community for their contributions and support.

external-resolver's People

Contributors

leonardovieira1630 avatar pikonha avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

ohhkaneda

external-resolver's Issues

[L2] Create contract for Arbitrum reading (Part.2)

Feature Request

We need to have an smart contract deployed on any given layer 2 protocol to be used as an external source which will be used on the redirecting phase of the L1 flow.

sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :setText("test.eth", "avatar", "avatar.png")
  Resolver->>Client :revert `StorageHandledByL2(chainId, contractAddress)`
  Client->>⭐ L2 Contract :setText("test.eth", "avatar", "avatar.png")

Describe Preferred Solution

The L2 contract should behave exactly the same way as Public Resolver would in the Layer 1.

Address reading implementation

/**
    * Returns the address associated with an ENS node.
    * @param node The ENS node to query.
    * @return The associated address.
    */
function addr(
    bytes32 node
) public view virtual override returns (address payable) {
    bytes memory a = addr(node, COIN_TYPE_ETH);
    if (a.length == 0) {
        return payable(0);
    }
    return bytesToAddress(a);
}

Checklist

  • Deploy offchain resolver contract on the Layer 2.

Related Code

Public Resolver contract implementation
Offchain Resolving
Address reading implementation

Additional Context

After being deployed to the given layer 2, the contract address should be stored in the layer 1 contract in order to redirect the requests by using StorageHandledByL2(chainID, contractAddress).

[L2] Create contract for Arbitrum reading (Part.1)

Feature Request

We need to have an smart contract deployed on any given layer 2 protocol to be used as an external source which will be used on the redirecting phase of the L1 flow.

sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :setText("test.eth", "avatar", "avatar.png")
  Resolver->>Client :revert `StorageHandledByL2(chainId, contractAddress)`
  Client->>⭐ L2 Contract :setText("test.eth", "avatar", "avatar.png")

Describe Preferred Solution

The L2 contract should behave exactly the same way as Public Resolver would in the Layer 1.

Address reading implementation

/**
    * Returns the address associated with an ENS node.
    * @param node The ENS node to query.
    * @return The associated address.
    */
function addr(
    bytes32 node
) public view virtual override returns (address payable) {
    bytes memory a = addr(node, COIN_TYPE_ETH);
    if (a.length == 0) {
        return payable(0);
    }
    return bytesToAddress(a);
}

Checklist

  • Run local node with Layer 2.

Related Code

Public Resolver contract implementation
Offchain Resolving
Address reading implementation

Additional Context

After being deployed to the given layer 2, the contract address should be stored in the layer 1 contract in order to redirect the requests by using StorageHandledByL2(chainID, contractAddress).

Create contracts subpackage

Feature Request

Describe the Feature Request

All the smart contracts should be placed in a single subpackage on the monorepo structure, allowing commands to be run from the root in order to automate local dev environment setup and mainnet/testnet deploy.

The ENS architecture is composed by multiple components, however the ones that are most important for the name resolution and data storage are the Registry, Universal Resolver and Public Resolver.

Describe Preferred Solution

Use Foundry as the Solidity framework due its simplicity and performance.

The contracts package must implement the following features:

  • Testing all contracts with filtering option
  • Deploying locally and to mainnet/testnet
  • Run local node for development

The following contracts are required to be present on the environment in order to resolve a name and to read/write its properties.

Describe Alternatives

Hardhat is an alternative giving its community adoption and TS native support.

Related Code

Foundry Book
Registry deployment script
Offchain Resolver
Setting resolver on a given domain

Onchain writing on layer 1

Feature Request

We should be able to write data from the native layer 1 ENS solution. This will be the foundation for the future offchain implementations.

Describe Preferred Solution

The client needs to be able to call the Registry for getting the given domain's Resolver for then to set properties stored onchain.

sequenceDiagram
    Client->>Registry: resolver("test.eth")
    Registry->>Client: L1 Contract address
    Client->>L1 Contract: setText("test.eth", "key", "value")
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'
 
const client = createWalletClient({
  chain: mainnet,
  transport: http()
})

const hash = await walletClient.sendTransaction({ 
  account,
  to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
  value: 1000000000000000000n
})

Additional Context

The writing isn't yet supported by the most popular ENS SDK's, therefore it will require the requests to be made using the JSON-RPC API

Blocked by #11

Implement Husky git hooks

Feature Request

Automate usual tasks to enforce repo standards.

Describe Preferred Solution

Use Husky to implement git hooks.
Some useful tasks to be run on a git hook:

  • Run tests on pre-push
  • Looks for leaked private keys on changed files
  • Generate commit message based on changed files
  • Run linter

Describe Alternatives

Rely only on Github Actions.

[DB] Read ENS properties from database on gateway

Feature Request

After implementing the read information from a Database feature, it will be necessary to create some integration tests. The tests will be responsibly to ensure that the flow of interaction between each part of the project is working properly and test bad scenarios to see how the code handles it.

Describe Preferred Solution

To complete this issue, it is be necessary the following tests:

  • Main flow of reading information from Database as specified in the image at the additional context;
  • Flow with a error in the final validation step;
  • Contract's address not exist;
  • Wrong calls in the resolver contract;

Additional Context

The right expected flow of interactions is the following one:

Captura de Tela 2024-02-23 às 15 08 30

Integration test for reading L2

Feature Request

The task objective is to finish the integration tests, and make the client able to read data from layer two. All this flow needs to be done in a test script.

Describe Preferred Solution

To do so, it is necessary to implement the gateway connection to l2 and to deploy the Public resolver in the Layer 2.

Related Code

#46
#47

Blockful's demo day

Feature Request

To resume the progress of the ENS team, the roadmap and the tasks that we will be working on next, it is necessary to make a demonstration for all blockful's members.

Describe Preferred Solution

To finish the issue, it is important to complete the following steps:

  • Overview about what is ENS.
  • What kind of problem Blockful is working on to solve.
  • How this work contributes with layers two.
  • What is our planned code architecture.
  • Overview about the code.

Additional Context

Blockful's ENS repository: https://github.com/blockful-io/external-resolver

ENS Team's board: https://github.com/orgs/blockful-io/projects/6

Onchain reading from layer 1

Feature Request

We should be able to read data from the native layer 1 ENS solution. This will be the foundation for the future offchain implementations.

Describe Preferred Solution

The client needs to be able to call the Registry for getting the given domain's Resolver for then to read its properties stored onchain.

sequenceDiagram
    Client->>Registry: resolver("test.eth")
    Registry->>Client: L1 Contract address
    Client->>L1 Contract: resolve("test.eth")
    L1 Contract->>Client: 0x....

Additional Context

The reading should be pretty straightforward giving that the SDKs support the layer 1 reading and writing by default.

Related Code

Blocked by #11

Implement the monorepo structure

Feature Request

Describe the Feature Request

We need to have a way to coordinate multiple entities of the project in a smooth way, which means being able to deploy them locally, test and improve each component seamlessly.

Describe Preferred Solution

Create a monorepo by using Turborepo where each different entity is a subpackage which their own set of dependencies and scripts.

We should be able to perform the following tasks seamlessly:

  • Build all packages
  • Run tests on all packages
  • Run tests on a specific package

Describe Alternatives

  1. to have different repositories for each different entity (contracts, client, gateway)
  2. to find an alternative for Turborepo such as yarn workspaces

[L2] Create contract for Optimism reading

Feature Request

We need to have an smart contract deployed on any given layer 2 protocol to be used as an external source which will be used on the redirecting phase of the L1 flow.

sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :setText("test.eth", "avatar", "avatar.png")
  Resolver->>Client :revert `StorageHandledByL2(chainId, contractAddress)`
  Client->>⭐ L2 Contract :setText("test.eth", "avatar", "avatar.png")

Describe Preferred Solution

The L2 contract should behave exactly the same way as Public Resolver would in the Layer 1.

Address reading implementation

/**
    * Returns the address associated with an ENS node.
    * @param node The ENS node to query.
    * @return The associated address.
    */
function addr(
    bytes32 node
) public view virtual override returns (address payable) {
    bytes memory a = addr(node, COIN_TYPE_ETH);
    if (a.length == 0) {
        return payable(0);
    }
    return bytesToAddress(a);
}

Checklist

  • Deploy contract on L2
  • Set L2 contract address on L1 contract

Related Code

Public Resolver contract implementation
Offchain Resolving
Address reading implementation

Additional Context

After being deployed to the given layer 2, the contract address should be stored in the layer 1 contract in order to redirect the requests by using StorageHandledByL2(chainID, contractAddress).

Integration tests (core)

Feature Request

Implement an integrated test for the project, aiming to integrate the existing components: Client, Gateway, Registry Contract on layer 1 (L1), and the Offchain-Resolver Contract, also from layer 1. This test is designed to establish the complete flow of interactions between these components, serving as a solid foundation for future integrated tests.

Describe Preferred Solution

Develop a comprehensive integrated test script, preferably written in TypeScript, that will act as a client and perform the following actions:

  • Start the server (gateway).
  • Deploy the contracts (registry and resolver).
  • Make a call to the registry and receive the callback with the resolver's address.
  • Make a call to the resolver and receive the callback with the offchain address of the gateway.
  • Make a call to the gateway.

This script should effectively simulate the end-to-end flow of interactions between the specified components, validating their integration and ensuring a comprehensive understanding of the system's functionality.

Related Code

  • External Resolver Repository: This repository contains the structure of the Resolver that should be utilized for integration.
  • Example E2E Test: Here, you can find an example of an end-to-end test using the specified contract. This can serve as a reference for implementing the integrated test in your project.
  • EVM Gateway Repository: This repository contains the implementation of a gateway and some tests that can serve as inspiration for your project.

Implement Gateway subpackage

Feature Request

Describe the Feature Request

The Gateway logic should be placed in a subpackage on the monorepo structure, allowing commands to be run from the root package in order automate local development environment setup.

The gateway is a part of our project architecture that aims to obtain state proofs of information coming from an EVM. It is through this system that the status check is currently carried out.

An important thing to note is that it will be necessary to have a gateway for each chain that we want to communicate with. In the case of this first task, we will communicate with layer 1.

  • Create a gateway that enhance the EVMgateway class.
  • Create gateway to handle ens methods for writing and reading.
  • Server to run the component locally.
  • Script to test the gateway.

Describe Preferred Solution

Knowing that we already have the standard gateway structure, we must import it and create a legacy gateway that communicates and validates with layer 1. This same type of structure that communicates with layer 1 will be used as the basis for our offchain implementations.

To be considered a valid external data source on the offchain resolving flow, there are requirements that need to be met that will enable off chain resolution as well as storage of additional properties of ENS' domains, such as avatar and com.twitter.

The gateway must implement the following methods:

  • Any methods from the ENS' Interface Standard
    • setAddr(bytes32 node, address addr): setting Ethereum address
    • addr(bytes32 node, uint coinType) view returns (byte memory): reading a multicoin address
    • setText(bytes32 node, string calldata key, string calldata value): setting a text record
    • text(bytes32 node, string key) view returns (string memory): reading a text record

Related Code

Additional Context

There are no need for the Gateway to implement all the methods specified by ENS' Interface Standard, although each of them enables a new feature that is natively support by the ENS onchain resolution flow.

Still unclear whether the client should call setText() straight from the Gateway after the first resolve() call, or call the smart contract expecting for a StorageHandleByOffchainDatabase revert.

Create contract for Gateway reading and writing

Feature Request

The ENS storage of properties related to a domain or subdomains can be handled by Offchain gateway, an API that exposes a REST endpoint (see below) and saves its content into a data source that can be pretty much anything.

Describe Preferred Solution

The Gateway should expose a REST endpoint that follows either of the following patterns as defined in ERC-3668:

  • GET /{sender}/{data}.json
  • POST /{sender}.json body: {data}
sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :resolve("test.eth")
  Resolver->>Client :revert `StorageHandledByOffchainDatabase(sender, url, calldata)`
  Client->>Gateway :GET `/{sender}/{data}.json`
  Gateway->>Client :200 OK
  • The sender is the smart contract address and its version.
  • The url is the Gateway's URL so the Client can redirect the request
  • The calldata is the encoded information of the domain such as owner address, namehash, and parameters

Smart contract implementation

function setAddr(bytes32 node, address a) external {
    IWriteDeferral.parameter[] memory params = new IWriteDeferral.parameter[](3);

    params[0].name = "node";
    params[0].value = BytesToString.bytes32ToString(node);

    params[1].name = "coin_type";
    params[1].value = Strings.toString(coinType);

    params[2].name = "address";
    params[2].value = BytesToString.bytesToString(a);

    revert StorageHandledByOffChainDatabase(
        IWriteDeferral.domainData(
            {
                name: WRITE_DEFERRAL_DOMAIN_NAME,
                version: WRITE_DEFERRAL_DOMAIN_VERSION,
                chainId: 1,
                verifyingContract: address(this)
            }
        ),
        _offChainDatabaseUrl,
        IWriteDeferral.messageData(
            {
                functionSelector: msg.sig,
                sender: msg.sender,
                parameters: params,
                expirationTimestamp: block.timestamp + _offChainDatabaseTimeoutDuration
            }
        )
    );
}

Describe Alternatives

The /{sender}/{data}.json is a pattern created for reading data offchain, which doesn't necessarily attend to the writing requirements. If so, a new pattern could be created and applied as a new EIP, giving that the EIP-5559 is still under discussion in the community.

Related Code

Smart contract implementation

Additional Context

No offchain writing implementation has been found so far.

Integration test: reading from database

Feature Request

After implementing the read and signing information on a Database feature, it will be necessary to create some integration tests. The tests will be responsible for ensuring that the flow of interaction between each part of the project is working properly and testing bad scenarios to see how the code handles it.

Describe Preferred Solution

To complete this issue, it is necessary the following tests:

  • Setup local environment for testing
    • Run gateway
    • Run local node
      • Deploy ENS Registry
      • Deploy Offchain Resolver
    • Seed test database with mock data

Test Scenarios

  • Read avatar URL
  • Read arbitrary text record
  • Read contenthash
  • Read address Ethereum
  • Read address Bitcoin

Additional Context

The right expected flow of interactions is the following:

Image

Gateway signing messages on reading (Part.1)

The gateway should sign messages read from any external datasource to proof its authenticity on the smart OffchainResolver smart contract.

  • Gateway has its own private key
  • It read data from an external datasource (DB, L2)
  • It signs the read data with it's private key so the contract can proof that it came from the right place

refactor: integration tests to use vitest instead jest

Refactor Request

Describe the Refactor Request

In the integration tests branch, it was used jest. Otherwise, in some parts of the project, it is being used vitest, that is newer and more performative.
So, to make a more concise and more performative code, the integration tests need to be refactored.

Describe Preferred Solution

To complete the issue, the integration test needs to import vitest functions and definitions, like beforeAll, it and describe. None of jest definitions will be used after the modification.

Related Code

An example of test the is using the vitest already can be seen at: https://github.com/blockful-io/external-resolver/blob/integrationTests/packages/client/test/public.test.ts

Additional Context

vitest docs: https://vitest.dev/guide/

[L2] Read ENS properties from L2 on gateway

Feature Request

After implementing the read information from a layer 2 feature, it will be necessary to create some integration tests. The tests will be responsibly to ensure that the flow of interaction between each part of the project is working properly and test bad scenarios to see how the code handles it.

Describe Preferred Solution

To complete this issue, it is be necessary the following tests:

  • Main flow of reading information from layer 2 as specified in the image at the additional context;
  • Flow with a error in the final validation step;
  • Contract's address not exist;
  • Wrong calls in the resolver contract;

Additional Context

The right expected flow of interactions is the following one:

Captura de Tela 2024-02-23 às 14 50 21

Create architecture diagrams

Feature Request

Describe the Feature Request

To start building the project, it will be needed to plan all the flow of interactions between each part. So, the ideia of this task is to create some diagrams that represents the code structure, architecture and flow.

Describe Preferred Solution

To achieve the mentioned goal, the task will be broke into 4 pieces:

  • Project architecture for Layer 2 communication
  • Project architecture for Database communication
  • Interaction flow between project parts for Layer 2 communication
  • Interaction flow between project parts for Database communication

Integration tests for writing (Database)

Feature Request

After implementing the write information on a Database feature, it will be necessary to create some integration tests. The tests will be responsibly to ensure that the flow of interaction between each part of the project is working properly and test bad scenarios to see how the code handles it.

Describe Preferred Solution

To complete this issue, it is be necessary the following tests:

  • Main flow of writing information on the Database as specified in the image at the additional context;
  • Contract's address not exist;
  • Wrong calls in the resolver contract;

Additional Context

The right expected flow of interactions is the following one:

Captura de Tela 2024-02-23 às 15 20 39

Gateway validate ownership of writing calls

Feature Request

The gateway should be able to receive encoded data from the Client with a signature for proofing it came from a given address in order to ensure ownership allowing changes to be made only by the property owner.

Implement Client logic for offchain writing on layer 2

Feature Request

The client should be able to call the writing methods of a contract deployed on a layer 2 protocol to be used as an external source which will be used on the redirecting phase of the L1 flow.

sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :text("test.eth", "avatar", "avatar.png")
  Resolver->>Client :revert `StorageHandledByL2(chainId, contractAddress)`
  Client->> L2 Contract :text("test.eth", "avatar", "avatar.png")

Describe Preferred Solution

The client should be able to:

  1. Call any writing method on the L1 contract
  2. Handle the L1's StorageHandledByL2 revert
  3. Call the given method on the L2 contract

Related Code

Public Resolver contract implementation
Offchain Resolving
Address reading implementation
Read data validation

Additional context

No implementation of the CCIP-Read on Layer 2 has been found so far. The most popular JS libraries (Viem and Ethers) currently only support the Gateway reading.

No validation is required on the writing phase according to EIP-5559.

[DB] Implement Layer 1 contract that redirects to a Gateway

Feature Request

Describe the Feature Request

In order to support offchain writing, the layer 1 smart contract should redirect the writing call to an external URL by relying on the StorageHandleByOffchainDatabase error as defined in EIP-5559.

Describe Preferred Solution

The highlighted step is responsible for informing the client that the storage of the given ENS entity is held by an off-chain data source (a.k.a. Gateway).

┌──────┐                                           ┌───────────┐  ┌────────────────────┐
│Client│                                           │L1 Contract│  │ Off-Chain Database │
└──┬───┘                                           └─────┬─────┘  └──────────┬─────────┘
   │                                                     │                   │ 
   │ somefunc(...)                                       │                   │ 
   ├────────────────────────────────────────────────────►│                   │ 
   │                                                     │                   │ 
   │ ⭐ revert StorageHandledByOffChainDatabase(sender,  |                   │ 
   │                               urls, requestParams)  │                   │ 
   │◄────────────────────────────────────────────────────┤                   │ 
   │                                                     │                   │ 
   │ HTTP Request [requestParams, signature]             │                   │ 
   ├─────────────────────────────────────────────────────┼──────────────────►│ 
   │                                                     │                   │ 
   │ response                                            │                   │ 
   │◄────────────────────────────────────────────────────┼───────────────────┤ 
   │                                                     │                   │ 

The redirecting is done by reverting the contract call with the arguments specified by EIP-5559. In order to have access to such entities within the layer 1, the contract should implement the IWriteDeferral interface defined in here.

  • sender: the address of the smart contract that redirected the request to the gateway
  • data: the calldata
    • contract version

       /**
       * @notice Struct used to define the domain of the typed data signature, defined in EIP-712.
       * @param name The user friendly name of the contract that the signature corresponds to.
       * @param version The version of domain object being used.
       * @param chainId The ID of the chain that the signature corresponds to (ie Ethereum mainnet: 1, Goerli testnet: 5, ...). 
       * @param verifyingContract The address of the contract that the signature pertains to.
       */
       struct domainData {
           string name;
           string version;
           uint64 chainId;
           address verifyingContract;
       }   
    • url: Gateway's URL (e.g.: https://localhost:8080/{sender}/{data}.json

    • sender

        /**
        * @notice Struct used to define the message context used to construct a typed data signature, defined in EIP-712, 
        * to authorize and define the deferred mutation being performed.
        * @param functionSelector The function selector of the corresponding mutation.
        * @param sender The address of the user performing the mutation (msg.sender).
        * @param parameter[] A list of <key, value> pairs defining the inputs used to perform the deferred mutation.
        */
        struct messageData {
            bytes4 functionSelector;
            address sender;
            parameter[] parameters;
            uint256 expirationTimestamp;
        }
      
        /**
        * @notice Struct used to define a parameter for Off-Chain Database Handler deferral.
        * @param name The variable name of the parameter.
        * @param value The string encoded value representation of the parameter.
        */
        struct parameter {
            string name;
            string value;
        }

Related Code

Additional Context

It is important to notice that the EIP-5559 still under discussion on the Ethereum community and isn't yet an widely adopted standard.

Implement offchain reading from Gateway on Client

Feature Request

We need to have an API that is compliant to the ENS' Gateway Interface to be used as an external source which will be used on the redirecting phase of the L1 flow.

sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :text("test.eth", "avatar")
  Resolver->>Client :revert StorageHandledByOffchainDatabase(sender, url, message)
  Client->>Gateway :GET /{sender}/{encode(text("test.eth", "avatar"))}.json
  Gateway->>Client :200 ok {response}
  Client->>Resolver :callback(response, message.callbackData)

Describe Preferred Solution

The ERC-3668 specification requires the read data from any offchain data source to be validated on the layer 1 by calling a callback function with the Gateway's response and the callbackData.

Client read and callback validation:

const result = await ccipFetch({ data: callData, sender, urls }) // Gateway call

const { data: data_ } = await call(client, { // L1 data validation
  blockNumber,
  blockTag,
  data: concat([
    callbackSelector,
    encodeAbiParameters(
      [{ type: 'bytes' }, { type: 'bytes' }],
      [result, extraData],
    ),
  ]),
  to,
} as CallParameters)

return data_!

Layer 1 data validation:

/**
* Callback used by CCIP read compatible clients to verify and parse the response.
*/
function resolveWithProof(bytes calldata response, bytes calldata extraData) external view returns(bytes memory) {
    (address signer, bytes memory result) = SignatureVerifier.verify(extraData, response);
    require(
        signers[signer],
        "SignatureVerifier: Invalid sigature");
    return result;
}

Checklist

  • Call L1 Registry: resolver("test.eth")
  • Call L1 Resolver: text("test.eth", "com.twitter")
  • Handle StorageHandledByOffchainDatabase(sender, url, message) error
  • Call Gateway: GET /{sender}/{encode(text("test.eth", "com.twitter"))}.json
  • Validate response on L1 Resolver: callback(response, callbackData)

Related Code

Public Resolver contract implementation
Offchain Resolving
Address reading implementation
Read data validation

Integration tests for writing (Layer 2)

Feature Request

After implementing the write information on a Layer 2 feature, it will be necessary to create some integration tests. The tests will be responsibly to ensure that the flow of interaction between each part of the project is working properly and test bad scenarios to see how the code handles it.

Describe Preferred Solution

To complete this issue, it is be necessary the following tests:

  • Main flow of writing information on the Layer 2 as specified in the image at the additional context;
  • Contract's address not exist;
  • Wrong calls in the resolver contract;

Additional Context

The right expected flow of interactions is the following one:

Captura de Tela 2024-02-23 às 15 24 17

Workshop ENS theoretical part

Feature Request

One core part of the workshop that will be done in 20/03/2024 at the ETHSamba, is the theoretical one. In this part, it will be taught the following aspects:

  • Introduction to Ethereum addresses and concepts
  • What's ENS, and what problem is it solving? Who is using it?
  • ENS and DNS
  • How to buy a domain? Why are there 2 transactions?
  • Explain primary name, subdomains, records
  • Contracts architecture (controller, registry, resolver, off-chain resolver)

Additional Context

ENS website: https://app.ens.domains

Validate Gateway inheritance possibility

Feature Request

It is needed to implement a proof generation and validation in the gateway that communicates with the layer two. To do so, we will test the viability of inherit the EVM Gateway properties and functions on our own gateway.
This task aim to answer if it is possible or not to do this process.

Describe Preferred Solution

We want to instantiate the gateway in the format we are currently doing. In other words, preferably we only want to modify the newApp function than it can import the EVMGateway and uses its structure. The function code should look something like this:

export function NewApp(
  handlers: ccip.HandlerDescription[],
  middlewares: RequestHandler[],
) {
  const server = NewServer(...handlers, withQuery())
  const l1Provider = process.env.LAYER_ONE_RPC
  const l2Provider = process.env.LAYER2_RPC
  const l2Rollup = '0xd80810638dbDF9081b72C1B33c65375e807281C8'

  const evmGateway = new EVMGateway(
    new ArbProofService(
      new JsonRpcProvider(l1Provider),
      new JsonRpcProvider(l2Provider),
      l2Rollup,
      new InMemoryBlockCache(),
    ),
  )
  evmGateway.add(server)

  return server.makeApp('/', ...middlewares)
}

Describe Alternatives

There are two possible Alternatives.

  • Include EVM Gateway repository as a git submodule in our repository. Then, import the gateway structure and use it with our gateway.
git submodule add https://github.com/ensdomains/evmgateway
  • Clone the EVM Gateway repository in our repository. This will not allow us to be update to the evmGateway modifications, but allow us to modificate their code and make the files more custom.
cd packages && git clone https://github.com/ensdomains/evmgateway

Related Code

For the task, it is important to undrustand and take a look at EVM Gateway code:
https://github.com/ensdomains/evmgateway

Make the repository compliant to the open source standards

Proposed solution

We need to have a repository that follows all the community standards as an open source project which means:

  • Add repository description
  • Add README.md
  • Implement code of conduct
  • Implement CONTRIBUITING.md
  • Add license file
  • Implement security policy
  • Implement pull request template
  • Set code owners
  • Create milestones and subtasks

Workshop ENS practical part

Feature Request

One core part of the workshop that will be done in 20/03/2024 at the ETHSamba, is the practical one. In this part, it will be taught the following aspects:

  • Buy domain in testnet.
  • Deploy a Public Resolver contract on the testnet.
  • Use ENS front end to point the deployed resolver and fetch information.
  • Explain what we are doing at Blockful and how can they contribute.

Describe Preferred Solution

1 - Setup local envirolment:

  • Download necessary libs, code editor and frameworks.
  • Get eth by some faucet.
  • Buy a testnet ENS domain.

2 - Deploy contracts:

  • Clone github repository's project.
  • Deploy Public Resolver with a deploy script.

3 - Fetch information with the ENS's frontend:

  • Get deployed contract's address.
  • Set the resolver's address in the frontend.
  • Confirm that the front end is reaching the contract and getting the information.

4 - What are we doing at Blockful?

  • Explain what we are working on and how can they contribute.

Additional Context

It still is some parts of the task that we needed to think about. Like:

  • What kind of libs, frameworks and code editors will be used?
  • What faucet will be used?
  • We will deploy the front end, or use a deployed one?

Also, here it is some important links to complete the task:

Faucet exemple: https://www.alchemy.com/faucets/ethereum-sepolia

how to use ENS testnet: https://phi-xyz.notion.site/Get-a-ENS-domain-on-Goerli-Testnet-6563298f8abc445d9a20472db05aef79

ENS frontend: https://app.ens.domains

ENS contracts: https://github.com/ensdomains/ens-contracts

Plan workshop structure and content

Feature Request

Plan ENS workshop that will be done in ETHSamba at march 22 to 24. The goal of the workshop is to onboard new developers to the ENS.

Describe Preferred Solution

To achieve the our goal, we will talk about the following subjects related to the ENS.

Theoric: #45

  • Introduction to Ethereum addresses and concepts
  • What's ENS, and what problem is it solving? Who is using it?
  • ENS and DNS
  • How to buy a domain? Why are there 2 transactions?
  • Explain primary name, subdomains, records
  • Contracts architecture (controller, registry, resolver, off-chain resolver)

Practical: #43

  • Buy domain in testnet.
  • Deploy public resolver // Deploy offchainResolver
  • Explain what we are doing and how can they contribute.

Additional Context

[L2] Call l2 on gateway

Feature Request

We need to have an smart contract deployed on any given layer 2 protocol to be used as an external source which will be used on the redirecting phase of the L1 flow.

sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :text("test.eth", "avatar", "avatar.png")
  Resolver->>Client :revert `StorageHandledByL2(chainId, contractAddress)`
  Client->> L2 Contract :text("test.eth", "avatar", "avatar.png")

Describe Preferred Solution

The client should be able to:

  1. Connect to L2
  2. Call the given method on the L2 contract
  3. Return response

To complete this issue, it is be necessary the following steps:

  • L2 gateway file.
  • L2 repository class.
  • Script to deploy on arbitrum L1.
  • Script to deploy on arbitrum L2.
  • Resolver contract for arbitrum on layer 2.
  • Get functions implemented.

Related Code

Public Resolver contract implementation
Offchain Resolving
Address reading implementation
Read data validation

Additional context

No implementation of the CCIP-Read on Layer 2 has been found so far. The most popular JS libraries (Viem and Ethers) currently only support the Gateway reading.

We're not sure about whether the L2 response validation on L1 will be made through the callback (e.g. resolveWithProof) or via Merkle Proof.

Implement resolver writing methods on Gateway

Feature Request

Describe the Feature Request

As specified by the ERC-5559, the gateway should implement the methods we plan to support (such as setAddr(bytes32 node, address addr) and setText(bytes32 node, string calldata key, string calldata value)).

Describe Preferred Solution

The gateway must be able to receive writing functions as stablished by the ENS documentation by following the CCIP-Read-Server implementation. These are the arguments provided by the L1 smart contract when a writing call is supposed to be handled offchain (see EIP-5559):

  • sender: the address of the smart contract that redirected the request to the gateway
  • data: the calldata containing (see EIP-5559)
    • contract version

       /**
       * @notice Struct used to define the domain of the typed data signature, defined in EIP-712.
       * @param name The user friendly name of the contract that the signature corresponds to.
       * @param version The version of domain object being used.
       * @param chainId The ID of the chain that the signature corresponds to (ie Ethereum mainnet: 1, Goerli testnet: 5, ...). 
       * @param verifyingContract The address of the contract that the signature pertains to.
       */
       struct domainData {
           string name;
           string version;
           uint64 chainId;
           address verifyingContract;
       }   
    • url: Gateway's URL (e.g.: https://localhost:8080/{sender}/{data}.json

    • sender

        /**
        * @notice Struct used to define the message context used to construct a typed data signature, defined in EIP-712, 
        * to authorize and define the deferred mutation being performed.
        * @param functionSelector The function selector of the corresponding mutation.
        * @param sender The address of the user performing the mutation (msg.sender).
        * @param parameter[] A list of <key, value> pairs defining the inputs used to perform the deferred mutation.
        */
        struct messageData {
            bytes4 functionSelector;
            address sender;
            parameter[] parameters;
            uint256 expirationTimestamp;
        }
      
        /**
        * @notice Struct used to define a parameter for Off-Chain Database Handler deferral.
        * @param name The variable name of the parameter.
        * @param value The string encoded value representation of the parameter.
        */
        struct parameter {
            string name;
            string value;
        }

Related Code

Additional Context

No writing gateway implementation was found so far.

Architecture diagram:
Image

Implement `transfer` function on gateway for transferring subdomains ownership

Feature Request

The user should be able to transfer its domains to any given address as long as the ownership is validated.

Describe Preferred Solution

The function signature looks like this:

function transfer(signature: string, address: string, domain: string) : Promise<void>;

This function follows the ERC-712 NFT standard and the underlying implementation should change the domain's owner address to the given one.

The signature is required to validate the ownership of the address before transferring it.

Implement Client subpackage

Feature Request

The client is responsible for linking different components that compose the ENS Offchain architecture. Therefore, a package named client will be required to gather all its specific logic, as well as its tests and scripts if needed.

┌──────┐                                           ┌───────────┐  ┌────────────────────┐
│Client│                                           │L1 Contract│  │ Off-Chain Database │
└──┬───┘                                           └─────┬─────┘  └──────────┬─────────┘
   │                                                     │                   │ 
   │ somefunc(...)                                       │                   │ 
   ├────────────────────────────────────────────────────►│                   │ 
   │                                                     │                   │ 
   │  revert StorageHandledByOffChainDatabase(sender,    |                   │ 
   │                               urls, requestParams)  │                   │ 
   │◄────────────────────────────────────────────────────┤                   │ 
   │                                                     │                   │ 
   │ HTTP Request [requestParams, signature]             │                   │ 
   ├─────────────────────────────────────────────────────┼──────────────────►│ 
   │                                                     │                   │ 
   │ response                                            │                   │ 
   │◄────────────────────────────────────────────────────┼───────────────────┤ 
   │                                                     │                   │ 

Describe Preferred Solution

The Client logic should be placed in a subpackage on the monorepo structure, allowing commands to be run from the root package in order automate local development environment setup. This subpackage must be able to:

  • Connect to a given Blockchain network through an JSON-RPC client
  • Call specific methods of an smart contract

Related Code

Implement Github Actions

Feature Request

Describe the Feature Request

The repository should automatically enforce the specified requirements in order to accept the addition of a change into the codebase. This will avoid repetitive manual tasks, leaking of private information, crashing of the master branch and merging of untested code.

Describe Preferred Solution

Implement Github Actions for:

  • running tests
  • enforce test coverage

Describe Alternatives

Some of these requirements could be enforced by using Husky git hooks.

Gateway sign read data (Part.2)

The gateway should sign messages read from any external datasource to prove its authenticity on the smart OffchainResolver smart contract.

  • It signs the read data with its private key so the contract can prove that it came from the right place

[L2] Create contract for L2 writing

Feature Request

The ENS storage of properties related to a domain or subdomains can be handled by a different network than Ethereum.

Describe Preferred Solution

The layer 2 contract should follow the ENS' Public Resolver interface.

sequenceDiagram
  Client->>Registry :resolver("test.eth")
  Registry->>Client :0x....
  Client->>Resolver :setText("test.eth", "avatar", "avatar.png")
  Resolver->>Client :revert `StorageHandledByL2(chainId, contractAddress)`
  Client->>L2 Contract :setText("test.eth", "avatar", "avatar.png")
  • The chainId is the layer 2 network ID
  • The contractAddress is the Resolver's address on the layer2

Smart Contract Implementation

function setAddr(bytes32 node, address a) external {
   revert StorageHandledByL2(
      10,
      _l2HandlerContractAddress
   ); 
}

Related Code

ENS Public Resolver
L2 contract implementation

Additional Context

The ownership offchain validation is still under discussion. The question is:

How can we ensure that the offchain domain properties are only being changed by its real owner?

Implement `mint` function on gateway for creating new subdomains

Feature Request

Implement the mint function that enables the creation of new subdomains stored off-chain.

Describe Preferred Solution

The function signature looks like this:

function mint(address: string, node: string) : Promise<void>;

It follows the ERC-712 NFT standard. The underlying implementation should create a new domain on the domains table with the given address as owner.

Implement Offchain Resolver

Feature Request

Currently, our contracts consist in the Public Resolver and Registry. However, to enable the redirection of users to an offchain address, it is imperative to implement the Offchain Resolver contract. The Offchain Resolver will allow offchain interactions what is very important to our project's goal.

Describe Preferred Solution

The preferred solution involves implementing the Offchain Resolver contracts, as outlined in the ensdomains/offchain-resolver repository. These contracts are designed to provide offchain resolution of ENS names and are in compliance with ENSIP 10 (wildcard resolution support) and EIP 3668 (CCIP Read).

  • Deploy and Offchain Resolver.
  • Test the contracts by getting an offchain url as a call response.

Related Code

  • Offchain Resolver Contracts: In this directory, you will find the Solidity contracts defining the Offchain Resolver. These contracts include IExtendedResolver.sol, SignatureVerifier.sol, and OffchainResolver.sol.

  • TestOffchainResolver.js: This JavaScript file contains a test suite for the Offchain Resolver. Reviewing this test can provide valuable insights into how the resolver contracts are intended to be used and tested.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.