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

Disallow duplicate tenderizers for the same validator #74

Merged
merged 2 commits into from
Jan 4, 2024
Merged
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
"scripts": {
"clean": "rimraf cache out",
"lint": "yarn lint:sol && yarn prettier:write",
"lint:sol": "yarn solhint \"{src,test,script}/**/*.sol\"",
"lint:sol": "yarn solhint \"{src}/**/*.sol\"",
"postinstall": "husky install",
"prettier:check": "prettier --check \"**/*.{json,md,yml}\"",
"prettier:write": "prettier --write \"**/*.{json,md,yml}\""
}
}
}
1 change: 1 addition & 0 deletions src/factory/Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ contract Factory {
tenderizer = address(tenderizerImpl).clone(abi.encodePacked(asset, validator));

// Reverts if caller is not a registered factory
// Reverts if `validator` already has a registered `tenderizer` for `asset`
Registry(registry).registerTenderizer(asset, validator, tenderizer);
}
}
38 changes: 27 additions & 11 deletions src/registry/Registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { Adapter } from "core/adapters/Adapter.sol";
contract Registry is Initializable, UUPSUpgradeable, AccessControlUpgradeable, RegistryStorage {
error InvalidAdapter(address adapter);
error InvalidTreasury(address treasury);
error TenderizerAlreadyExists(address asset, address validator, address tenderizer);

event AdapterRegistered(address indexed asset, address indexed adapter);
event NewTenderizer(address indexed asset, address indexed validator, address tenderizer);
Expand Down Expand Up @@ -57,6 +58,14 @@ contract Registry is Initializable, UUPSUpgradeable, AccessControlUpgradeable, R

// Getters

/**
* @notice Returns the address of the adapter for a given asset
* @param asset Address of the underlying asset
*/
function adapter(address asset) external view returns (address) {
return _loadStorage().protocols[asset].adapter;
}

/**
* @notice Returns the address of the tenderizer implementation
*/
Expand All @@ -66,19 +75,19 @@ contract Registry is Initializable, UUPSUpgradeable, AccessControlUpgradeable, R
}

/**
* @notice Returns the address of the unlocks contract
* @notice Returns the address of the treasury
*/
function unlocks() external view returns (address) {
function treasury() external view returns (address) {
Storage storage $ = _loadStorage();
return $.unlocks;
return $.treasury;
}

/**
* @notice Returns the address of the adapter for a given asset
* @param asset Address of the underlying asset
* @notice Returns the address of the unlocks contract
*/
function adapter(address asset) external view returns (address) {
return _loadStorage().protocols[asset].adapter;
function unlocks() external view returns (address) {
Storage storage $ = _loadStorage();
return $.unlocks;
}

/**
Expand All @@ -99,11 +108,13 @@ contract Registry is Initializable, UUPSUpgradeable, AccessControlUpgradeable, R
}

/**
* @notice Returns the address of the treasury
* @notice Returns the address of the tenderizer for a given asset and validator
* @param asset Address of the underlying asset
* @param validator Address of the validator
* @return Address of the tenderizer
*/
function treasury() external view returns (address) {
Storage storage $ = _loadStorage();
return $.treasury;
function getTenderizer(address asset, address validator) external view returns (address) {
return _loadStorage().tenderizers[asset][validator];
}

// Setters
Expand All @@ -129,6 +140,11 @@ contract Registry is Initializable, UUPSUpgradeable, AccessControlUpgradeable, R
* @param tenderizer Address of the tenderizer
*/
function registerTenderizer(address asset, address validator, address tenderizer) external onlyRole(FACTORY_ROLE) {
Storage storage $ = _loadStorage();
if ($.tenderizers[asset][validator] != address(0)) {
revert TenderizerAlreadyExists(asset, validator, $.tenderizers[asset][validator]);
}
$.tenderizers[asset][validator] = tenderizer;
_grantRole(TENDERIZER_ROLE, tenderizer);
emit NewTenderizer(asset, validator, tenderizer);
}
Expand Down
1 change: 1 addition & 0 deletions src/registry/RegistryStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ contract RegistryStorage {
address unlocks;
address treasury;
mapping(address => Protocol) protocols;
mapping(address asset => mapping(address validator => address tenderizer)) tenderizers;
}

function _loadStorage() internal pure returns (Storage storage $) {
Expand Down
10 changes: 10 additions & 0 deletions test/registry/Registry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,16 @@ contract RegistryTest is Test {
assertEq(registry.hasRole(TENDERIZER_ROLE, tenderizer), true);
}

function test_RegisterTenderizer_RevertsIfExists() public {
vm.prank(owner);
registry.grantRole(FACTORY_ROLE, factory);
vm.startPrank(factory);
registry.registerTenderizer(asset, account, tenderizer);
vm.expectRevert(abi.encodeWithSelector(Registry.TenderizerAlreadyExists.selector, asset, account, tenderizer));
registry.registerTenderizer(asset, account, makeAddr("SECOND_TENDERIZER"));
vm.stopPrank();
}

function test_RegisterTenderizer_RevertIfNotFactory() public {
vm.prank(owner);
vm.expectRevert();
Expand Down
Loading