Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lockable resolver #262

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
36 changes: 35 additions & 1 deletion contracts/resolvers/ResolverBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ pragma solidity >=0.8.4;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./profiles/IVersionableResolver.sol";

error NotAuthorised();
error NotClearable();

abstract contract ResolverBase is ERC165, IVersionableResolver {
mapping(bytes32 => uint64) public recordVersions;
mapping(bytes32 => bool) private unclearable;
mapping(bytes32 => bool) private allRecordsLocked;

event AllRecordsLocked(bytes32 indexed node);

function isAuthorised(bytes32 node) internal view virtual returns (bool);

modifier authorised(bytes32 node) {
require(isAuthorised(node));
if (!isAuthorised(node)) {
revert NotAuthorised();
}
_;
}

Expand All @@ -20,10 +29,35 @@ abstract contract ResolverBase is ERC165, IVersionableResolver {
* @param node The node to update.
*/
function clearRecords(bytes32 node) public virtual authorised(node) {
if (unclearable[node]) {
revert NotClearable();
}
recordVersions[node]++;
emit VersionChanged(node, recordVersions[node]);
}

/**
* Returns true if all records for this node have been locked.
* @param node The node to check.
*/
function isAllLocked(bytes32 node) public view virtual returns (bool) {
return allRecordsLocked[node];
}

/**
* Locks all records for this ENS node.
* @param node The ENS node to lock.
*/
function lockAll(bytes32 node) public virtual authorised(node) {
allRecordsLocked[node] = true;
_setUnclearable(node);
emit AllRecordsLocked(node);
}

function _setUnclearable(bytes32 node) internal {
unclearable[node] = true;
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
Expand Down
27 changes: 27 additions & 0 deletions contracts/resolvers/profiles/ABIResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ pragma solidity >=0.8.4;
import "./IABIResolver.sol";
import "../ResolverBase.sol";

error ABIIsLocked();

abstract contract ABIResolver is IABIResolver, ResolverBase {
mapping(uint64 => mapping(bytes32 => mapping(uint256 => bytes))) versionable_abis;
mapping(bytes32 => bool) abi_locks;

event ABILocked(bytes32 indexed node);

/**
* Sets the ABI associated with an ENS node.
Expand All @@ -20,6 +25,10 @@ abstract contract ABIResolver is IABIResolver, ResolverBase {
uint256 contentType,
bytes calldata data
) external virtual authorised(node) {
if (isABILocked(node)) {
revert ABIIsLocked();
}

// Content types must be powers of 2
require(((contentType - 1) & contentType) == 0);

Expand Down Expand Up @@ -59,6 +68,24 @@ abstract contract ABIResolver is IABIResolver, ResolverBase {
return (0, bytes(""));
}

/**
* Returns true if the ABI has been locked for this ENS node.
* @param node The ENS node to check.
*/
function isABILocked(bytes32 node) public view virtual returns (bool) {
return abi_locks[node] || isAllLocked(node);
}

/**
* Locks the ABI for this ENS node.
* @param node The node to lock.
*/
function lockABI(bytes32 node) public virtual authorised(node) {
abi_locks[node] = true;
_setUnclearable(node);
emit ABILocked(node);
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
Expand Down
26 changes: 26 additions & 0 deletions contracts/resolvers/profiles/AddrResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import "../ResolverBase.sol";
import "./IAddrResolver.sol";
import "./IAddressResolver.sol";

error AddrIsLocked();

abstract contract AddrResolver is
IAddrResolver,
IAddressResolver,
Expand All @@ -13,6 +15,9 @@ abstract contract AddrResolver is
uint256 private constant COIN_TYPE_ETH = 60;

mapping(uint64 => mapping(bytes32 => mapping(uint256 => bytes))) versionable_addresses;
mapping(bytes32 => bool) addr_locks;

event AddrLocked(bytes32 indexed node);

/**
* Sets the address associated with an ENS node.
Expand Down Expand Up @@ -47,6 +52,9 @@ abstract contract AddrResolver is
uint256 coinType,
bytes memory a
) public virtual authorised(node) {
if (isAddrLocked(node)) {
revert AddrIsLocked();
}
emit AddressChanged(node, coinType, a);
if (coinType == COIN_TYPE_ETH) {
emit AddrChanged(node, bytesToAddress(a));
Expand All @@ -61,6 +69,24 @@ abstract contract AddrResolver is
return versionable_addresses[recordVersions[node]][node][coinType];
}

/**
* Returns true if addresses have been locked for this ENS node.
* @param node The ENS node to check.
*/
function isAddrLocked(bytes32 node) public view virtual returns (bool) {
return addr_locks[node] || isAllLocked(node);
}

/**
* Locks the addresses for this ENS node.
* @param node The node to lock.
*/
function lockAddr(bytes32 node) public virtual authorised(node) {
addr_locks[node] = true;
_setUnclearable(node);
emit AddrLocked(node);
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
Expand Down
28 changes: 28 additions & 0 deletions contracts/resolvers/profiles/ContentHashResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./IContentHashResolver.sol";

error ContenthashIsLocked();

abstract contract ContentHashResolver is IContentHashResolver, ResolverBase {
mapping(uint64 => mapping(bytes32 => bytes)) versionable_hashes;
mapping(bytes32 => bool) contenthash_locks;

event ContenthashLocked(bytes32 indexed node);

/**
* Sets the contenthash associated with an ENS node.
Expand All @@ -17,6 +22,9 @@ abstract contract ContentHashResolver is IContentHashResolver, ResolverBase {
bytes32 node,
bytes calldata hash
) external virtual authorised(node) {
if (isContenthashLocked(node)) {
revert ContenthashIsLocked();
}
versionable_hashes[recordVersions[node]][node] = hash;
emit ContenthashChanged(node, hash);
}
Expand All @@ -32,6 +40,26 @@ abstract contract ContentHashResolver is IContentHashResolver, ResolverBase {
return versionable_hashes[recordVersions[node]][node];
}

/**
* Returns true if the contenthash has been locked for this ENS node.
* @param node The ENS node to check.
*/
function isContenthashLocked(
bytes32 node
) public view virtual returns (bool) {
return contenthash_locks[node] || isAllLocked(node);
}

/**
* Locks the contenthash for this ENS node.
* @param node The node to lock.
*/
function lockContenthash(bytes32 node) public virtual authorised(node) {
contenthash_locks[node] = true;
_setUnclearable(node);
emit ContenthashLocked(node);
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
Expand Down
30 changes: 30 additions & 0 deletions contracts/resolvers/profiles/DNSResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import "../../dnssec-oracle/RRUtils.sol";
import "./IDNSRecordResolver.sol";
import "./IDNSZoneResolver.sol";

error DNSIsLocked();

abstract contract DNSResolver is
IDNSRecordResolver,
IDNSZoneResolver,
Expand All @@ -31,6 +33,10 @@ abstract contract DNSResolver is
mapping(uint64 => mapping(bytes32 => mapping(bytes32 => uint16)))
private versionable_nameEntriesCount;

mapping(bytes32 => bool) dns_locks;

event DNSLocked(bytes32 indexed node);

/**
* Set one or more DNS records. Records are supplied in wire-format.
* Records with the same node/name/resource must be supplied one after the
Expand All @@ -54,6 +60,9 @@ abstract contract DNSResolver is
bytes32 node,
bytes calldata data
) external virtual authorised(node) {
if (isDNSLocked(node)) {
revert DNSIsLocked();
}
uint16 resource = 0;
uint256 offset = 0;
bytes memory name;
Expand Down Expand Up @@ -145,6 +154,9 @@ abstract contract DNSResolver is
bytes32 node,
bytes calldata hash
) external virtual authorised(node) {
if (isDNSLocked(node)) {
revert DNSIsLocked();
}
uint64 currentRecordVersion = recordVersions[node];
bytes memory oldhash = versionable_zonehashes[currentRecordVersion][
node
Expand All @@ -164,6 +176,24 @@ abstract contract DNSResolver is
return versionable_zonehashes[recordVersions[node]][node];
}

/**
* Returns true if the DNS records have been locked for this ENS node.
* @param node The ENS node to check.
*/
function isDNSLocked(bytes32 node) public view virtual returns (bool) {
return dns_locks[node] || isAllLocked(node);
}

/**
* Locks the DNS records for this ENS node.
* @param node The node to lock.
*/
function lockDNS(bytes32 node) public virtual authorised(node) {
dns_locks[node] = true;
_setUnclearable(node);
emit DNSLocked(node);
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
Expand Down
28 changes: 28 additions & 0 deletions contracts/resolvers/profiles/InterfaceResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ import "../ResolverBase.sol";
import "./AddrResolver.sol";
import "./IInterfaceResolver.sol";

error InterfaceIsLocked();

abstract contract InterfaceResolver is IInterfaceResolver, AddrResolver {
mapping(uint64 => mapping(bytes32 => mapping(bytes4 => address))) versionable_interfaces;
mapping(bytes32 => bool) interface_locks;

event InterfaceLocked(bytes32 indexed node);

/**
* Sets an interface associated with a name.
Expand All @@ -21,6 +26,9 @@ abstract contract InterfaceResolver is IInterfaceResolver, AddrResolver {
bytes4 interfaceID,
address implementer
) external virtual authorised(node) {
if (isInterfaceLocked(node)) {
revert InterfaceIsLocked();
}
versionable_interfaces[recordVersions[node]][node][
interfaceID
] = implementer;
Expand Down Expand Up @@ -75,6 +83,26 @@ abstract contract InterfaceResolver is IInterfaceResolver, AddrResolver {
return a;
}

/**
* Returns true if the interfaces have been locked for this ENS node.
* @param node The ENS node to check.
*/
function isInterfaceLocked(
bytes32 node
) public view virtual returns (bool) {
return interface_locks[node] || isAllLocked(node);
}

/**
* Locks the interfaces for this ENS node.
* @param node The node to lock.
*/
function lockInterface(bytes32 node) public virtual authorised(node) {
interface_locks[node] = true;
_setUnclearable(node);
emit InterfaceLocked(node);
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
Expand Down
26 changes: 26 additions & 0 deletions contracts/resolvers/profiles/NameResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./INameResolver.sol";

error NameIsLocked();

abstract contract NameResolver is INameResolver, ResolverBase {
mapping(uint64 => mapping(bytes32 => string)) versionable_names;
mapping(bytes32 => bool) name_locks;

event NameLocked(bytes32 indexed node);

/**
* Sets the name associated with an ENS node, for reverse records.
Expand All @@ -16,6 +21,9 @@ abstract contract NameResolver is INameResolver, ResolverBase {
bytes32 node,
string calldata newName
) external virtual authorised(node) {
if (isNameLocked(node)) {
revert NameIsLocked();
}
versionable_names[recordVersions[node]][node] = newName;
emit NameChanged(node, newName);
}
Expand All @@ -32,6 +40,24 @@ abstract contract NameResolver is INameResolver, ResolverBase {
return versionable_names[recordVersions[node]][node];
}

/**
* Returns true if the name has been locked for this ENS node.
* @param node The ENS node to check.
*/
function isNameLocked(bytes32 node) public view virtual returns (bool) {
return name_locks[node] || isAllLocked(node);
}

/**
* Locks the name for this ENS node.
* @param node The node to lock.
*/
function lockName(bytes32 node) public virtual authorised(node) {
name_locks[node] = true;
_setUnclearable(node);
emit NameLocked(node);
}

function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
Expand Down
Loading