Skip to content

Commit

Permalink
fix: [audit] ZNS-18 Approved Resolvers List (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtulloch authored Nov 3, 2023
2 parents 5b97484 + bb9c7ec commit a3acd34
Show file tree
Hide file tree
Showing 11 changed files with 1,793 additions and 1,701 deletions.
22 changes: 7 additions & 15 deletions contracts/registrar/IZNSRootRegistrar.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ pragma solidity 0.8.18;
import { IDistributionConfig } from "../types/IDistributionConfig.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";


/**
* @notice Stake fee is 0x0 for anything other than subdomain under a parent with Stake Payment
* parent hash will be 0x0 for root domain
*/
struct CoreRegisterArgs {
// 0x0 for root domains
bytes32 parentHash;
bytes32 domainHash;
string label;
address registrant;
address domainAddress;
uint256 price;
// 0x0 for anything other than subdomain under a parent with Stake Payment
uint256 stakeFee;
address domainAddress;
string label;
string tokenURI;
bool isStakePayment;
}
Expand Down Expand Up @@ -114,19 +115,12 @@ interface IZNSRootRegistrar is IDistributionConfig {
*/
event SubRegistrarSet(address subRegistrar);

/**
* @notice Emitted when the `addressResolver` address is set in state.
* @param addressResolver The new address of the AddressResolver contract
*/
event AddressResolverSet(address addressResolver);

function initialize(
address accessController_,
address registry_,
address rootPricer_,
address treasury_,
address domainToken_,
address addressResolver_
address domainToken_
) external;

function registerRootDomain(
Expand Down Expand Up @@ -155,6 +149,4 @@ interface IZNSRootRegistrar is IDistributionConfig {
function setDomainToken(address domainToken_) external;

function setSubRegistrar(address subRegistrar_) external;

function setAddressResolver(address addressResolver_) external;
}
806 changes: 395 additions & 411 deletions contracts/registrar/ZNSRootRegistrar.sol

Large diffs are not rendered by default.

35 changes: 33 additions & 2 deletions contracts/registry/IZNSRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ interface IZNSRegistry {
bool allowed
);

/**
* @notice Emitted when a new resolver type is added to ZNS
* @param resolverType The name of the resolver type
* @param resolver The address of the resolver contract
*/
event ResolverAdded(
string resolverType,
address resolver
);

/**
* @notice Emitted when a resolver is deleted from ZNS
* @param resolverType The name of the resolver type
*/
event ResolverDeleted(
string resolverType
);

function initialize(address accessController) external;

function exists(bytes32 domainHash) external view returns (bool);
Expand Down Expand Up @@ -100,20 +118,33 @@ interface IZNSRegistry {
function createDomainRecord(
bytes32 domainHash,
address owner,
string calldata resolverType
) external;

function getResolverType(
string calldata resolverType
) external returns (address);

function addResolverType(
string calldata resolverType,
address resolver
) external;

function deleteResolverType(
string calldata resolverType
) external;

function updateDomainRecord(
bytes32 domainHash,
address owner,
address resolver
string calldata resolverType
) external;

function updateDomainOwner(bytes32 domainHash, address owner) external;

function updateDomainResolver(
bytes32 domainHash,
address resolver
string calldata resolverType
) external;

function deleteRecord(bytes32 domainHash) external;
Expand Down
61 changes: 48 additions & 13 deletions contracts/registry/ZNSRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils
* Owner of a domain in this contract also serves as the owner of the stake in `ZNSTreasury`.
*/
contract ZNSRegistry is AAccessControlled, UUPSUpgradeable, IZNSRegistry {

// Mapping of all approved resolvers
mapping(string resolverType => address resolver) internal resolvers;

/**
* @notice Mapping of `domainHash` to [DomainRecord](./IZNSRegistry.md#iznsregistry) struct to hold information
* about each domain
Expand Down Expand Up @@ -154,21 +158,50 @@ contract ZNSRegistry is AAccessControlled, UUPSUpgradeable, IZNSRegistry {
* Emits `DomainOwnerSet` and possibly `DomainResolverSet` events.
* @param domainHash The hash of the domain name
* @param owner The owner of the new domain
* @param resolver The resolver of the new domain, can be 0
* @param resolverType The string identifier of the resolver for the new domain, e.g. "address"
*/
function createDomainRecord(
bytes32 domainHash,
address owner,
address resolver
string calldata resolverType
) external override onlyRegistrar {
_setDomainOwner(domainHash, owner);

// We allow creation of partial domain data with no resolver address
if (resolver != address(0)) {
_setDomainResolver(domainHash, resolver);
if (bytes(resolverType).length != 0) {
_setDomainResolver(domainHash, resolverType);
}
}

/**
* @notice Given a resolver type, returns the address of the resolver contract for that type or 0x0 if not found
* @param resolverType The resolver type as a string, e.g. "address"
*/
function getResolverType(string calldata resolverType) public view override returns(address) {
return resolvers[resolverType];
}

/**
* @notice Add a new resolver type option to the mapping of types
* This function can also be used to update the resolver mapping for an existing resolver
* simple by using an existing key like "address" with a new address
* @param resolverType The type of the resolver to add
* @param resolver The address of the new resolver contract
*/
function addResolverType(string calldata resolverType, address resolver) public override onlyAdmin {
resolvers[resolverType] = resolver;
emit ResolverAdded(resolverType, resolver);
}

/**
* @notice Delete a resolver type from the mapping of types
* @param resolverType The type to be removed
*/
function deleteResolverType(string calldata resolverType) public override onlyAdmin {
delete resolvers[resolverType];
emit ResolverDeleted(resolverType);
}

/**
* @notice Updates an existing domain record's owner and resolver.
* Note that this function can ONLY be called by the Name owner of the domain.
Expand All @@ -178,16 +211,16 @@ contract ZNSRegistry is AAccessControlled, UUPSUpgradeable, IZNSRegistry {
* Emits `DomainOwnerSet` and `DomainResolverSet` events.
* @param domainHash The hash of the domain
* @param owner The owner or an allowed operator of that domain
* @param resolver The resolver for the domain
* @param resolverType The resolver for the domain
*/
function updateDomainRecord(
bytes32 domainHash,
address owner,
address resolver
string calldata resolverType
) external override onlyOwner(domainHash) {
// `exists` is checked implicitly through the modifier
_setDomainOwner(domainHash, owner);
_setDomainResolver(domainHash, resolver);
_setDomainResolver(domainHash, resolverType);
}

/**
Expand All @@ -212,16 +245,16 @@ contract ZNSRegistry is AAccessControlled, UUPSUpgradeable, IZNSRegistry {

/**
* @notice Updates the resolver of an existing domain in `records`.
* Can be called by eithe the owner of the Name or an allowed operator.
* Can be called by either the owner of the Name or an allowed operator.
* @param domainHash the hash of a domain's name
* @param resolver The new Resolver contract address
* @param resolverType The new Resolver contract address
*/
function updateDomainResolver(
bytes32 domainHash,
address resolver
string calldata resolverType
) external override onlyOwnerOrOperator(domainHash) {
// `exists` is checked implicitly through the modifier
_setDomainResolver(domainHash, resolver);
_setDomainResolver(domainHash, resolverType);
}

/**
Expand Down Expand Up @@ -262,12 +295,14 @@ contract ZNSRegistry is AAccessControlled, UUPSUpgradeable, IZNSRegistry {
* @notice Internal function to set a domain's resolver in state `records`.
* Resolver can be set to 0, since we allow partial domain data. Emits a `DomainResolverSet` event.
* @param domainHash the hash of a domain's name
* @param resolver The resolver to set
* @param resolverType The resolver to set
*/
function _setDomainResolver(
bytes32 domainHash,
address resolver
string calldata resolverType
) internal {
address resolver = resolvers[resolverType];

records[domainHash].resolver = resolver;
emit DomainResolverSet(domainHash, resolver);
}
Expand Down
7 changes: 6 additions & 1 deletion test/ZNSAddressResolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
import { hashDomainLabel, hashSubdomainName } from "./helpers/hashing";
import {
ADMIN_ROLE,
DEFAULT_RESOLVER_TYPE,
GOVERNOR_ROLE,
REGISTRAR_ROLE,
deployZNS,
Expand Down Expand Up @@ -45,11 +46,13 @@ describe("ZNSAddressResolver", () => {

await zns.accessController.connect(deployer).grantRole(REGISTRAR_ROLE, mockRegistrar.address);

await zns.registry.connect(deployer).addResolverType(DEFAULT_RESOLVER_TYPE, zns.addressResolver.address);

await zns.registry.connect(mockRegistrar)
.createDomainRecord(
wilderDomainHash,
deployer.address,
zns.addressResolver.address
DEFAULT_RESOLVER_TYPE
);
});

Expand All @@ -70,7 +73,9 @@ describe("ZNSAddressResolver", () => {
// The domain exists
const existResolver = await zns.registry.getDomainResolver(wilderDomainHash);
expect(existResolver).to.eq(zns.addressResolver.address);
});

it("Returns 0 when the domain doesnt exist", async () => {
// The domain does not exist
const someDomainHash = hashDomainLabel("random-record");
const notExistResolver = await zns.registry.getDomainResolver(someDomainHash);
Expand Down
Loading

0 comments on commit a3acd34

Please sign in to comment.