Skip to content

Commit

Permalink
changed: alias mapping public, owner -> Ownable
Browse files Browse the repository at this point in the history
  • Loading branch information
steffenkux committed Dec 5, 2023
1 parent 965b1f1 commit f3c2cb2
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 352 deletions.
94 changes: 17 additions & 77 deletions packages/toplevel-alias/contracts/TopLevelAliasRegistry.sol
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title TopLevelAliasRegistry
* @dev A contract for managing a registry of aliases mapped to names.
* Allows a group of admins to set aliases for given names, ensuring aliases end with '.eth',
* have at least three characters before '.eth', do not exceed a maximum length, are not empty,
* and are valid ENS names.
* This contract allows the owner to set aliases for given names, ensuring aliases end with '.eth',
* have at least three characters before '.eth', do not exceed a maximum length, and are not empty.
*/
contract TopLevelAliasRegistry {
// Mapping of names to aliases
mapping(string => string) private aliases;

// Mapping of addresses to their admin status
mapping(address => bool) private admins;

// Counter for the number of admins
uint256 private adminCount;
contract TopLevelAliasRegistry is Ownable {
// Public mapping of names to aliases
mapping(string => string) public aliases;

// Maximum allowed length for an alias
uint256 private constant MAX_ALIAS_LENGTH = 100;
Expand All @@ -25,86 +20,29 @@ contract TopLevelAliasRegistry {
event AliasSet(string indexed _name, string _alias);

/**
* @dev Sets the deployer of the contract as an initial admin.
* @dev Constructor that sets the specified address as the owner of the contract.
* @param initialOwner The address to be set as the initial owner of the contract.
*/
constructor() {
admins[msg.sender] = true;
adminCount = 1;
constructor(address initialOwner) Ownable(initialOwner) {
}

/**
* @dev Sets an alias for a given name, ensuring it meets various criteria including ENS validity.
* Can only be called by an admin.
* Only the owner of the contract can call this function.
* Validates that the name is not empty, the alias length is within limits, and ends with '.eth'.
*
* @param _name The name to map the alias to. Must not be empty.
* @param _alias The alias to be set for the given name.
* @param _alias The alias to be set for the given name. Must meet the criteria.
*/
function setAlias(string memory _name, string memory _alias) public onlyAdmin {
function setAlias(string memory _name, string memory _alias) public onlyOwner {
require(bytes(_name).length > 0, "Name cannot be empty");
require(bytes(_alias).length >= 7, "Alias must be at least 7 characters long");
require(bytes(_alias).length <= MAX_ALIAS_LENGTH, "Alias is too long");
require(bytes(_alias).length >= 7 && bytes(_alias).length <= MAX_ALIAS_LENGTH, "Alias length is invalid");
require(_endsWith(_alias, ".eth"), "Alias must end with '.eth'");

aliases[_name] = _alias;

emit AliasSet(_name, _alias);
}

/**
* @dev Retrieves the alias for a given name.
*
* @param _name The name whose alias is to be retrieved.
* @return The alias corresponding to the given name.
*/
function getAlias(string memory _name) public view returns (string memory) {
return aliases[_name];
}

/**
* @dev Checks if a given address is an admin.
* This is a helper function to access the admin status from outside the contract.
*
* @param user The address to check for admin status.
* @return bool True if the address is an admin, false otherwise.
*/
function isAdmin(address user) public view returns (bool) {
return admins[user];
}

/**
* @dev Modifier to restrict functions to admin only access.
*/
modifier onlyAdmin() {
require(admins[msg.sender], "Only an admin can perform this action");
_;
}

/**
* @dev Adds or removes admin status for a given address.
* Ensures that there is always at least one admin.
* Can only be called by an existing admin.
*
* @param _user The address to grant or revoke admin status.
* @param _status The admin status to be set (true for admin, false otherwise).
*/
function setAdminStatus(address _user, bool _status) public onlyAdmin {
require(_user != address(0), "Invalid address");
require(adminCount > 1 || _status == true, "Cannot remove the last admin");
if (_status && !admins[_user]) {
adminCount++;
} else if (!_status && admins[_user]) {
adminCount--;
}
admins[_user] = _status;
}

/**
* @dev Internal function to check if a string ends with a specific suffix.
*
* @param _base The string to check.
* @param _value The suffix to look for.
* @return bool True if _base ends with _value, false otherwise.
*/
function _endsWith(string memory _base, string memory _value) internal pure returns (bool) {
bytes memory baseBytes = bytes(_base);
bytes memory valueBytes = bytes(_value);
Expand All @@ -122,3 +60,5 @@ contract TopLevelAliasRegistry {
return true;
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ pragma solidity ^0.8.0;
import "../contracts/TopLevelAliasRegistry.sol";

contract TestTopLevelAliasRegistry is TopLevelAliasRegistry {
constructor(address initialOwner) TopLevelAliasRegistry(initialOwner) {
}

function testEndsWith(string memory _base, string memory _value) public pure returns (bool) {
return _endsWith(_base, _value);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/toplevel-alias/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { HardhatUserConfig } from 'hardhat/config';
import '@nomicfoundation/hardhat-toolbox';

const config: HardhatUserConfig = {
solidity: '0.8.19',
solidity: '0.8.20',
gasReporter: {
enabled: process.env.REPORT_GAS !== undefined,
currency: 'USD',
Expand Down
8 changes: 8 additions & 0 deletions packages/toplevel-alias/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/toplevel-alias/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
"@nomicfoundation/hardhat-toolbox": "^3.0.0",
"hardhat": "^2.19.1",
"hardhat-gas-reporter": "^1.0.9"
},
"dependencies": {
"@openzeppelin/contracts": "^5.0.0"
}
}
30 changes: 15 additions & 15 deletions packages/toplevel-alias/scripts/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import { ethers } from "hardhat";
import { ethers } from 'hardhat';

async function main() {
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
const unlockTime = currentTimestampInSeconds + 60;
const currentTimestampInSeconds = Math.round(Date.now() / 1000);
const unlockTime = currentTimestampInSeconds + 60;

const lockedAmount = ethers.parseEther("0.001");
const lockedAmount = ethers.parseEther('0.001');

const lock = await ethers.deployContract("Lock", [unlockTime], {
value: lockedAmount,
});
const lock = await ethers.deployContract('Lock', [unlockTime], {
value: lockedAmount,
});

await lock.waitForDeployment();
await lock.waitForDeployment();

console.log(
`Lock with ${ethers.formatEther(
lockedAmount
)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}`
);
console.log(

Check failure on line 15 in packages/toplevel-alias/scripts/deploy.ts

View workflow job for this annotation

GitHub Actions / code-quality

Unexpected console statement
`Lock with ${ethers.formatEther(
lockedAmount,
)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}`,
);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
console.error(error);

Check failure on line 25 in packages/toplevel-alias/scripts/deploy.ts

View workflow job for this annotation

GitHub Actions / code-quality

Unexpected console statement
process.exitCode = 1;
});
Loading

0 comments on commit f3c2cb2

Please sign in to comment.