How to set avatar for subdomains upon registration?

Hey guys,

I am developing an app which allows users to create subdomains for certain domains which I own. I would like to attach certain avatars to my domains, and would like those avatars to be set for all subdomains and I do not want to allow those who buy the subdomains to be able to change those avatars.

How can I do this? Note: I am going to be using my own subdomainregistrar.



We have been wondering this as well…

We think one way would be to create a function like:

function setAvatar(bytes32 _node, bytes calldata _image) external {
// Check if the caller is the parent of the subdomain
require(msg.sender == ens.owner(ens.parent(_node)), “Only the parent can change the avatar”);

// Call the original setAvatar function from the parent contract
super.setAvatar(_node, _image);


or a custom fuse

function disallowOwnerAvatar(string memory name) public view returns (bool) {
bytes32 label = keccak256(bytes(name));
address owner = ENS(ensRegistry).owner(label);
address parentOwner = ENS(ensRegistry).owner(ENS(ensRegistry).resolver(label));

// Check if the owner has set the avatar
if (AvatarMetadata(avatarRegistry).avatarURI(owner) != "") {
    return true;

// Check if the parent has set the avatar
if (AvatarMetadata(avatarRegistry).avatarURI(parentOwner) == "") {
    return true;

return false;


with updated fuseChecks

function fuseChecks(bytes32 node, string memory name) internal view {
require(!disallowOwnerAvatar(name), “Avatar can only be set by parent”);
require(!FuseRegistry(fuseRegistry).isFuseBlown(node), “Node fuse blown”);
require(!FuseRegistry(fuseRegistry).isFuseBlown(0), “Global fuse blown”);

and update register function

function register(string calldata name, address owner, bytes32 label, bytes32 parent) external {
fuseChecks(keccak256(abi.encodePacked(parent, label)), name);

This is what we’ve been playing with but we’ve been meaning to ask the dev team the best way to do this…


You can accomplish this with a custom resolver contract. Then, when you create your subnames, also burn CANNOT_SET_RESOLVER.

Your custom resolver could be setup so that only the parent owner (you) can set the avatar, yet still allow the owner of the subname to set other records like their ETH address and so on.


Thank you!!!

So the only thing we need to do in the resolver is set the image URL, right? Also, how do we connect the custom resolver to the registrar?

It’s your custom resolver, so it’s up to you what you want to pre-set or restrict.

Instead of allowing users to pass in their own resolver, your registrar would always set the resolver to your custom contract whenever any sub is registered.


The default ENS resolver is 0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63 - you would clone this contract and then edit in/out any restrictions you would like to impose on the Subname, and then force all Subnames to resolve at the new resolver contract address that contains your cloned / edited resolver contract.

In your namewrapper contract you would specifiy that Subname owner does not have the right to edit resolver / set a custom resolver.


This is a resolver I just whipped up based on @serenae’s spec. I’ve only added a couple tests and haven’t built the subdomain registrar that would need to be coupled with, but should serve as example of how it can be done.

PSA: Not production ready code


Everything works okay, just a few issues. I removed the authorised modifier on setAvatar since I wasn’t able to call register on my registrar. I anyways wanted to remove it though, since I’d like anyone who calls register to be able to set the avatar. If I do things this way, are there any issues? I basically want to allow anyone to call register, but I don’t want them to be able to change the avatar once set (I know I have to burn the respective fuse, but is there anything else I should keep in mind?)

Next, when I try to edit my profile on the ENS website (v3), I get a notification saying that the resolver is out of date and I need to upgrade it. Why is this? (I am testing on goerli).

Finally, I have set my avatar, however it’s not showing as the profile picture on the ENS website. Does it take time to set, have specific file requirements, or could something else be the issue?


Sweet - thank you :rocket:

If you remove the authorised modifier it means absolutely anyone can call setAvatar, which i’m guessing isn’t what you want. You need resolver.setApprovalForAll(subdomainRegistrar.address, true) on the resolver for the parent name so it can set it for you.

1 Like

I do setApprovalForAll from the namewrapper so I don’t need to from the resolver. Also, I want only the people who buy the subdomain to be able to set the avatar, and I’ve set a modifier which only allows the registrar to call setAvatar.

Is that an okay solution? I’m most concerned with safety.

Also, any idea why I’m being asked to update the resolver in the ENS v3 website (I assume it’s a bug).

1 Like

Sorry yes you are right. Why did you need to remove authorised from the resolver then?

Yes this is likely a bug. We’ll look into it

1 Like

It doesn’t work otherwise. Here’s the contract with the authorised modifier which don’t work (I can’t call register):

Registrar: 0x19946e8Cc970b9763a7F69BAb332296492ef3EC3
Resolver: 0x264041fB1aaB17AA73A1BF1c32c77DE05bF09D4D

Here’s when I remove the authorized modifier (these do work):

Registrar: 0x144204D2592F34a98371E7950Ae3D36372A68bb9
Resolver: 0x83Eb1D1Db4399913676ab25fC3a080798968388C

I think i know why it’s not working. We don’t allow those approved on the NameWrapper to set records on the PublicResolver.

Can you try the following?

Resolver.setApprovalForAll(SubdomainRegistrar.address, true). This should let the subdomain registrar set the records on behalf of the parent.

It’s working, the issue was my image url was invalid.

Even without removing authorised? Great

Nope, not without removing authorised. I thought this answer was when I first asked why my avatar wasn’t displaying correctly.

Will try with authorised.


I am also not able to update records with this resolver. It says ‘current resolver not compatible with wrapped names’. Is this a bug?