Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
# 馃 Linear

Closes EFI-XXX
55 changes: 55 additions & 0 deletions src/contracts/L2Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,59 @@ 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) {
// If the node is the reverse lookup node, then the caller must be the reverse admin
if (msg.sender != REVERSE_ADMIN) revert NotAuthorized();
} else {
address _owner = _getOwner(_node);
if (_owner != address(0)) {
// If the node is owned by the ENSRegistry, then the caller must be an approved operator or the owner
if (!_isApprovedOperatorOrOwner(msg.sender, _owner)) revert NotAuthorized();
} else {
// If the node is not owned by the ENSRegistry, then it could be a wildcard and caller must be an approved
// operator or the owner of the parent node
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);
}

/// @inheritdoc IL2Resolver
function getRecord(bytes32 _node, string calldata _key) external view returns (bytes memory _data) {
_data = records[_node][_key];
}

/**
* @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);
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;
}
}
17 changes: 16 additions & 1 deletion src/interfaces/IENS.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 registry.
*/
interface IENS {}
interface IENS {
/**
* @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);
}
29 changes: 29 additions & 0 deletions src/interfaces/IL2Resolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,43 @@ 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;

/**
* @notice Retrieves raw bytes for a given node and key from the records mapping.
* @param _node The ENS node to retrieve the data for.
* @param _key The key to retrieve the data under.
* @return _data The data stored under the key. Returns empty bytes if the record is not found.
*/
function getRecord(bytes32 _node, string calldata _key) external view returns (bytes memory _data);

/*///////////////////////////////////////////////////////////////
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 {
/**
* @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