Best Practices for Registering New Schemas

Quick Intro

Before we begin with describing best practices in Schema design, we would like to point out that this is just a guide. You don’t have to follow it. There are no rules inside the protocol for how schemas can be designed or used!

However, EAS is likely to become more useful if builders and users coordinate around schemas and follow generally accepted protocols and conventions. Therefore we have started with a small list of best practices that we feel would be useful to the community.

Best Practices

[1] Don’t reinvent the wheel

In general, schemas are most useful when they are designed in a way that can be used by more Dapps than just the one you’re building.

When schemas are well designed and made for general use cases, they are most likely to grow and acquire big network effects!

Since all schemas are public, it’s always a good idea to check if a schema already exists that fits your use case. If you find a Schema that suits your needs, you can start attesting on it. (Note: In rare cases, you might come across schemas that have custom resolvers that disallow 3rd party attesters. In this case you could clone the Schema and just register it without a resolver)

A few common schemas already exist for:

You should only register a new schema if you’re sure that existing ones won’t be good enough for what you want to build.

[2] Naming conventions

When choosing variable names for your schema, we suggest using the camelCase style. For example:

  • bool isTrue is proper camelCase, NOT
  • bool Istrue or
  • bool IsTrue.

Variable names should be as short and succinct. For example, use ‘bool isTrue’ rather than ‘bool useThisToAttestIfSomethingIsTrueOrFalse’ and ‘bool like’ rather than ‘bool attestTrueIfYouLike’

[3] Design for everybody

Schemas are most useful when everyone can attest on them! For example, if you are building something where users can like something, you can use this commonly used Schema for liking (Schema #2 (Like) - 0x33e9...391fd). It’s a very simple schema with one variable named “bool like” .

With the exception of some rare use cases, it would not be good practice to register a “bool likeInsideMySuperApp” schema just for your app only. As you would lose network effects that would already exist with the existing “bool like” schema.

If there is something specific that you want your users to reference when they’re liking something, you can use the refUID field and the user can pass an existing attestation UID that would give context for what they’re liking.

Referenced attestations could be something specific to your Dapp. For exmaple, If you built an art gallery, you might have a Schema for cataloging art pieces.

Users could then attest using the generally accepted “bool like” schema and include a refUID of an existing attestation from the art catalog Schema that represents the ID of art they’re liking.

[4] Composable Schemas are Happy Schemas!

Can you design a schema in a way that might be useful to other Dapps that already exist?

If attestations on your Schema can be referenced by other Schemas using the refUID field for some special use cases, then they are more composable!

[5] Don’t be redundant, Design for Efficiency

Quick Tips:

  1. Did you know that attestations are already natively timestamped inside the protocol?

You don’t need to create a timestamp for your schema to know when attestations are made. Timestamps in Schemas should be used if referring to a time for your use case that’s unrelated to when the actual attestations are made.

  1. Recipient addresses are already native to the the EAS protocol!

When someone makes an attestation, they can include a recipient address to identify who the attestation is directed to. It’s generally unnecessary to add a recipient field inside a Schema unless it’s for more specialized use cases.

A Few Tips for Gas Efficiency

If your Schema is processing a ton of attestations, small increases in bytes can add up significantly in costs over time. Care should be taken in your schema design to minimize gas costs.

Choose Efficient Data Types

  1. Choose uint64 for timestamps instead of uint256: A uint64 value can store up to 2^64-1, which is more than enough for representing timestamps. Using uint64 instead of uint256 saves 24 bytes, reducing the gas cost.
  2. Use uint8 for limited options: Smaller uints like uint8 can be used to store a smaller integer values representing an option, reducing the gas cost compared to storing the entire string. Storing a role as a string would cost 7 * 68 = 476 gas (assuming “moderator”), while using an uint8 would only cost 16 gas, saving 460 gas.
  3. Convert strings into bytes32 values instead of using string: If the text you need to store is shorter than or equal to 32 characters, it’s more gas-efficient to use bytes32. For example, the string “Hello world!” is 12 characters long and would cost 12 68 = 816 gas for a string and 32 8 = 256 gas for a bytes32, saving you 560 gas.
  4. Use the smallest integer types that fit your data: Instead of always using uint256, consider using smaller integer types like uint8, uint16, or uint32 if the data range fits. Smaller integer types occupy less space, resulting in lower gas costs. However, if your integer is a number for a price or value of something, it’s typically best to use uint256.
  5. Use packed arrays to save gas: If you have multiple values of the same type, consider using an array (e.g., uint8[] or uint16[]). Packed arrays store elements consecutively, without padding, reducing gas costs.
  6. Use bool instead of integers for binary values: When storing binary values (true or false), use the bool type instead of integers. This can save space and reduce gas costs.
  7. Optimize for off-chain data storage when possible: If your schema includes large data sets or elements that don’t require on-chain verification, consider storing the data off-chain and only storing a reference (e.g., a bytes32 hash) on-chain. This can significantly reduce the gas costs associated with your schema.
  8. Use a modular design to your schema: Consider what is the absolute minimum required in your Schema and determine if it might be better to break down your schema into separate individual Schemas that can reference each other. If you have a schema field that won’t be used each time the attestation is made, it’s a good sign that it should be broken down into modular parts that are composed together using the refUID field when needed.
  9. Avoid redundant data: Check your schema to see if you have any redundant fields. For example, you might add an address field for the schema and be using it as a recipient of the attestation. This is redundant because every attestation has an optional recipient field that can be used.