Skip to content
Merged
48 changes: 48 additions & 0 deletions src/contracts/L2Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,52 @@ contract L2Resolver is IL2Resolver {
REVERSE_ADMIN = _reverseAdmin;
PARENT_NODE = _parentNode;
}

/// @inheritdoc IL2Resolver
function setRecord(bytes32 _node, string calldata _key, bytes calldata _value) external {
if (_node == REVERSE_LOOKUP_NODE) {
Comment thread
0xAustrian marked this conversation as resolved.
if (msg.sender != REVERSE_ADMIN) revert NotAuthorized();
} else {
address _owner = _getOwner(_node);
Comment thread
0xAustrian marked this conversation as resolved.
if (_owner != address(0)) {
if (!_isApprovedOperatorOrOwner(msg.sender, _owner)) revert NotAuthorized();
} else {
// If the node is not owned by the ENSRegistry, then it could be a wildcard
address _parentOwner = _getOwner(PARENT_NODE);
if (_parentOwner == address(0)) revert NotAuthorized();
if (!_isApprovedOperatorOrOwner(msg.sender, _parentOwner)) revert NotAuthorized();
}
}

records[_node][_key] = _value;
emit RecordSet(_node, _key, _value);
}

/**
* @notice Returns the owner of a node.
* @dev If the node is the NameWrapper, then the domain is wrapped and it gets the owner from the NameWrapper.
* @dev If the owner is missing, then the domain is not registered or it could be a wildcard node.
* @param _node The node to get the owner of.
* @return _owner The owner of the node. Returns address(0) if the node is not owned by the ENSRegistry.
*/
function _getOwner(bytes32 _node) private view returns (address _owner) {
_owner = ENS_REGISTRY.owner(_node);
if (_owner == address(0)) return address(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can safely remove this line, the behaviour will be the same.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would revert if the NAME_WRAPPER is not set since it would try to do NAME_WRAPPER.ownerOf(uint256(_node));, right?

Maybe we should validate that none of those addresses are zero in the constructor?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, do you mind adding that to another linear task?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. I removed the validation in this PR

if (_owner == address(NAME_WRAPPER)) {
_owner = NAME_WRAPPER.ownerOf(uint256(_node));
}
}

/**
* @notice Returns whether the caller is an owner or an approved operator for the owner
* @param _caller The address to check.
* @param _owner The owner of the node.
* @return _approved True if the _caller is an owner or an approved operator for the _owner, false otherwise.
*/
function _isApprovedOperatorOrOwner(address _caller, address _owner) private view returns (bool _approved) {
if (_owner == _caller) return true;
if (ENS_REGISTRY.isApprovedForAll(_owner, _caller)) return true;
if (address(NAME_WRAPPER) != address(0) && NAME_WRAPPER.isApprovedForAll(_owner, _caller)) return true;
return false;
Comment thread
0xAustrian marked this conversation as resolved.
Outdated
}
}
17 changes: 16 additions & 1 deletion src/interfaces/IENS.sol

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can import this repo as a package and use ENS and INameWrapper, wdyt?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worth it when we just need a few lines of code for the interfaces? wouldn't it make the contract bigger by importing all those additional functions?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, lets do it your way

Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,19 @@ pragma solidity 0.8.30;
* @author @defi-wonderland
* @notice Interface for the ENS registry.
*/
interface IENS {}
interface IENS {
Comment thread
0xItadaki marked this conversation as resolved.
/**
* @notice Returns the address that owns the specified node.
* @param _node The specified node.
* @return _address of the owner.
*/
function owner(bytes32 _node) external view returns (address _address);

/**
* @notice Query if an address is an authorized operator for another address.
* @param _owner The address that owns the records.
* @param _operator The address that acts on behalf of the owner.
* @return _approved True if `_operator` is an approved operator for `_owner`, false otherwise.
*/
function isApprovedForAll(address _owner, address _operator) external view returns (bool _approved);
}
21 changes: 21 additions & 0 deletions src/interfaces/IL2Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,35 @@ interface IL2Resolver {
EVENTS
//////////////////////////////////////////////////////////////*/

/**
* @notice Emitted when a record is set.
* @param _node The ENS node to store the data for.
* @param _key The key to store the data under.
* @param _value The data to store under the key.
*/
event RecordSet(bytes32 indexed _node, string indexed _key, bytes _value);

/*///////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/

/**
* @notice Thrown when the caller is not authorized to set a value for a node.
*/
error NotAuthorized();

/*///////////////////////////////////////////////////////////////
LOGIC
//////////////////////////////////////////////////////////////*/

/**
* @notice Sets raw bytes for a given node and key in the records mapping.
* @param _node The ENS node to store the data for.
* @param _key The key to store the data under.
* @param _value The data to store under the key.
*/
function setRecord(bytes32 _node, string calldata _key, bytes calldata _value) external;

/*///////////////////////////////////////////////////////////////
VARIABLES
//////////////////////////////////////////////////////////////*/
Expand Down
17 changes: 16 additions & 1 deletion src/interfaces/INameWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,19 @@ pragma solidity 0.8.30;
* @author @defi-wonderland
* @notice Interface for the ENS Name Wrapper.
*/
interface INameWrapper {}
interface INameWrapper {
Comment thread
0xItadaki marked this conversation as resolved.
/**
* @notice Gets the owner of a name
* @param _id Label as a string of the .eth domain to wrap
* @return _address The owner of the name
*/
function ownerOf(uint256 _id) external view returns (address _address);

/**
* @notice Query if an address is an authorized operator for another address.
* @param _owner The address that owns the records.
* @param _operator The address that acts on behalf of the owner.
* @return _approved True if `_operator` is an approved operator for `_owner`, false otherwise.
*/
function isApprovedForAll(address _owner, address _operator) external view returns (bool _approved);
}
Loading
Loading