-
Notifications
You must be signed in to change notification settings - Fork 3
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
[ZNS ZChain] String Resolver #106
Changes from 5 commits
3662fac
9f774a9
30d6e95
ef3b152
a237e61
b625249
e3ee2c3
09fed3b
96de554
a7e70c9
76925f9
2f48b22
f9d396d
71cceaf
e785ccf
953fc73
bbb8136
d689dcc
898ac60
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.18; | ||
|
||
|
||
interface IZNSStringResolver { | ||
/** | ||
* @param newString The new domain owner | ||
* @param domainHash The identifying hash of a domain's name | ||
*/ | ||
event StringSet(bytes32 indexed domainHash, string indexed newString); | ||
|
||
function supportsInterface(bytes4 interfaceId) external view returns (bool); | ||
|
||
function resolveDomainString(bytes32 domainHash) external view returns (string memory); | ||
|
||
function setString( | ||
bytes32 domainHash, | ||
string calldata newString | ||
) external; | ||
|
||
function getInterfaceId() external pure returns (bytes4); | ||
|
||
function setRegistry(address _registry) external; | ||
|
||
function initialize(address _accessController, address _registry) external; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.18; | ||
|
||
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; | ||
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; | ||
import { IZNSStringResolver } from "./IZNSStringResolver.sol"; | ||
import { AAccessControlled } from "../access/AAccessControlled.sol"; | ||
import { ARegistryWired } from "../registry/ARegistryWired.sol"; | ||
|
||
|
||
/** | ||
* @title The specific Resolver for ZNS that maps domain hashes to strings. | ||
*/ | ||
contract ZNSStringResolver is | ||
UUPSUpgradeable, | ||
AAccessControlled, | ||
ARegistryWired, | ||
ERC165, | ||
IZNSStringResolver { | ||
|
||
mapping(bytes32 domainHash => string resolvedString) internal domainStrings; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Called them resolvedString and resolvedStrings, which I dont like, to be honest. Tell me, if I'm wrong and have to find another name) |
||
|
||
/// @custom:oz-upgrades-unsafe-allow constructor | ||
constructor() { | ||
_disableInitializers(); | ||
} | ||
|
||
/** | ||
* @notice Initializer for the `ZNSStringResolver` proxy. | ||
* Note that setter functions are used instead of direct state variable assignments | ||
* to use access control at deploy time. Only ADMIN can call this function. | ||
* @param accessController_ The address of the `ZNSAccessController` contract | ||
* @param registry_ The address of the `ZNSRegistry` contract | ||
*/ | ||
function initialize(address accessController_, address registry_) external override initializer { | ||
_setAccessController(accessController_); | ||
setRegistry(registry_); | ||
} | ||
|
||
/** | ||
* @dev Returns string associated with a given domain name hash. | ||
* @param domainHash The identifying hash of a domain's name | ||
*/ | ||
function resolveDomainString( | ||
bytes32 domainHash | ||
) external view override returns (string memory) { | ||
return domainStrings[domainHash]; | ||
} | ||
|
||
/** | ||
* @dev Sets the string for a domain name hash. | ||
* @param domainHash The identifying hash of a domain's name | ||
* @param newString The new string to map the domain to | ||
*/ | ||
function setString( | ||
bytes32 domainHash, | ||
string calldata newString | ||
) external override { | ||
// only owner or operator of the current domain can set the string | ||
require( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using custom errors is more gas efficient. I know they aren't used in the other contracts but they have already been deployed, so maybe we can update that at some point but for now use them instead of if (!registry.IsOwnerOrOperator(domainHash, msg.sender)) {
revert CustomErrorName();
} |
||
registry.isOwnerOrOperator(domainHash, msg.sender) || | ||
// TODO: decide, whether the registrar can set a string | ||
accessController.isRegistrar(msg.sender), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please, remove the comment and L63. Registrar will not be able to set a string. only owner or operator can. |
||
"ZNSStringResolver: Not authorized for this domain" | ||
); | ||
|
||
domainStrings[domainHash] = newString; | ||
|
||
emit StringSet(domainHash, newString); | ||
} | ||
|
||
/** | ||
* @dev ERC-165 check for implementation identifier | ||
* @dev Supports interfaces IZNSStringResolver and IERC165 | ||
* @param interfaceId ID to check, XOR of the first 4 bytes of each function signature | ||
*/ | ||
function supportsInterface( | ||
bytes4 interfaceId | ||
) public view virtual override(ERC165, IZNSStringResolver) returns (bool) { | ||
return | ||
interfaceId == getInterfaceId() || | ||
super.supportsInterface(interfaceId); | ||
} | ||
|
||
/** | ||
* @dev Exposes IZNSStringResolver interfaceId | ||
*/ | ||
function getInterfaceId() public pure override returns (bytes4) { | ||
return type(IZNSStringResolver).interfaceId; | ||
} | ||
|
||
/** | ||
* @dev Sets the address of the `ZNSRegistry` contract that holds all crucial data | ||
* for every domain in the system. This function can only be called by the ADMIN. | ||
* @param _registry The address of the `ZNSRegistry` contract | ||
*/ | ||
function setRegistry(address _registry) public override(ARegistryWired, IZNSStringResolver) onlyAdmin { | ||
_setRegistry(_registry); | ||
} | ||
|
||
/** | ||
* @notice To use UUPS proxy we override this function and revert if `msg.sender` isn't authorized | ||
* @param newImplementation The implementation contract to upgrade to | ||
*/ | ||
// solhint-disable-next-line no-unused-vars | ||
function _authorizeUpgrade(address newImplementation) internal view override { | ||
accessController.checkGovernor(msg.sender); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.18; | ||
|
||
import { ZNSStringResolver } from "../../resolver/ZNSStringResolver.sol"; | ||
import { UpgradeMock } from "../UpgradeMock.sol"; | ||
|
||
/* solhint-disable-next-line */ | ||
contract ZNSStringResolverUpgradeMock is ZNSStringResolver, UpgradeMock {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,4 +28,7 @@ export const EXECUTOR_ROLE = ethers.solidityPackedKeccak256( | |
|
||
export const ResolverTypes = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would be better as an enum, then it would resolve the "TODO" comment you have below as these are just given values export enum ResolverTypes {
ADDRESS,
STRING
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that would require a Registry contract upgrade... |
||
address: "address", | ||
// TODO: Which word to use for a string type of resolver?? | ||
// eslint-disable-next-line id-blacklist | ||
string: "string", | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { BaseDeployMission, TDeployArgs } from "@zero-tech/zdc"; | ||
import { HardhatRuntimeEnvironment } from "hardhat/types"; | ||
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; | ||
import { DefenderRelayProvider } from "@openzeppelin/defender-sdk-relay-signer-client/lib/ethers"; | ||
import { IZNSContracts } from "../../campaign/types"; | ||
import { ProxyKinds, ResolverTypes } from "../../constants"; | ||
import { znsNames } from "./names"; | ||
|
||
|
||
export class ZNSStringResolverDM extends BaseDeployMission< | ||
HardhatRuntimeEnvironment, | ||
SignerWithAddress, | ||
DefenderRelayProvider, | ||
IZNSContracts | ||
> { | ||
proxyData = { | ||
isProxy: true, | ||
kind: ProxyKinds.uups, | ||
}; | ||
|
||
contractName = znsNames.stringResolver.contract; | ||
instanceName = znsNames.stringResolver.instance; | ||
|
||
async deployArgs () : Promise<TDeployArgs> { | ||
const { accessController, registry } = this.campaign; | ||
|
||
return [ | ||
await accessController.getAddress(), | ||
await registry.getAddress(), | ||
]; | ||
} | ||
|
||
async needsPostDeploy () { | ||
const { | ||
registry, | ||
stringResolver, | ||
} = this.campaign; | ||
|
||
const resolverInReg = await registry.getResolverType( | ||
ResolverTypes.string, | ||
); | ||
|
||
const needs = resolverInReg !== await stringResolver.getAddress(); | ||
const msg = needs ? "needs" : "doesn't need"; | ||
|
||
this.logger.debug(`${this.contractName} ${msg} post deploy sequence`); | ||
|
||
return needs; | ||
} | ||
|
||
async postDeploy () { | ||
const { | ||
registry, | ||
stringResolver, | ||
config: { | ||
deployAdmin, | ||
}, | ||
} = this.campaign; | ||
|
||
await registry.connect(deployAdmin).addResolverType( | ||
ResolverTypes.string, | ||
await stringResolver.getAddress(), | ||
); | ||
|
||
this.logger.debug(`${this.contractName} post deploy sequence completed`); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change the order of these.
also,
newString
comment is not correct. it's not the owner, it's the string that owner assigns which a domain will resolve to