Skip to content

Commit

Permalink
Merge pull request #30 from morpho-org/style/owner-naming
Browse files Browse the repository at this point in the history
owner => admin
  • Loading branch information
MathisGD authored Mar 5, 2024
2 parents 21a4ae4 + 01820d2 commit 14f37ed
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 38 deletions.
26 changes: 14 additions & 12 deletions src/PublicAllocator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ contract PublicAllocator is IPublicAllocatorStaticTyping {
/* STORAGE */

/// @inheritdoc IPublicAllocatorBase
mapping(address => address) public owner;
mapping(address => address) public admin;
/// @inheritdoc IPublicAllocatorBase
mapping(address => uint256) public fee;
/// @inheritdoc IPublicAllocatorBase
Expand All @@ -47,9 +47,11 @@ contract PublicAllocator is IPublicAllocatorStaticTyping {

/* MODIFIER */

/// @dev Reverts if the caller is not the owner for this vault or the vault owner.
modifier onlyOwner(address vault) {
if (msg.sender != owner[vault] && msg.sender != IMetaMorpho(vault).owner()) revert ErrorsLib.NotOwner();
/// @dev Reverts if the caller is not the admin nor the owner of this vault.
modifier onlyAdminOrVaultOwner(address vault) {
if (msg.sender != admin[vault] && msg.sender != IMetaMorpho(vault).owner()) {
revert ErrorsLib.NotAdminNorVaultOwner();
}
_;
}

Expand All @@ -60,24 +62,24 @@ contract PublicAllocator is IPublicAllocatorStaticTyping {
MORPHO = IMorpho(morpho);
}

/* OWNER ONLY */
/* ADMIN OR VAULT OWNER ONLY */

/// @inheritdoc IPublicAllocatorBase
function setOwner(address vault, address newOwner) external onlyOwner(vault) {
if (owner[vault] == newOwner) revert ErrorsLib.AlreadySet();
owner[vault] = newOwner;
emit EventsLib.SetOwner(msg.sender, vault, newOwner);
function setAdmin(address vault, address newAdmin) external onlyAdminOrVaultOwner(vault) {
if (admin[vault] == newAdmin) revert ErrorsLib.AlreadySet();
admin[vault] = newAdmin;
emit EventsLib.SetAdmin(msg.sender, vault, newAdmin);
}

/// @inheritdoc IPublicAllocatorBase
function setFee(address vault, uint256 newFee) external onlyOwner(vault) {
function setFee(address vault, uint256 newFee) external onlyAdminOrVaultOwner(vault) {
if (fee[vault] == newFee) revert ErrorsLib.AlreadySet();
fee[vault] = newFee;
emit EventsLib.SetFee(msg.sender, vault, newFee);
}

/// @inheritdoc IPublicAllocatorBase
function setFlowCaps(address vault, FlowCapsConfig[] calldata config) external onlyOwner(vault) {
function setFlowCaps(address vault, FlowCapsConfig[] calldata config) external onlyAdminOrVaultOwner(vault) {
for (uint256 i = 0; i < config.length; i++) {
if (config[i].caps.maxIn > MAX_SETTABLE_FLOW_CAP || config[i].caps.maxOut > MAX_SETTABLE_FLOW_CAP) {
revert ErrorsLib.MaxSettableFlowCapExceeded();
Expand All @@ -89,7 +91,7 @@ contract PublicAllocator is IPublicAllocatorStaticTyping {
}

/// @inheritdoc IPublicAllocatorBase
function transferFee(address vault, address payable feeRecipient) external onlyOwner(vault) {
function transferFee(address vault, address payable feeRecipient) external onlyAdminOrVaultOwner(vault) {
uint256 claimed = accruedFee[vault];
accruedFee[vault] = 0;
feeRecipient.transfer(claimed);
Expand Down
11 changes: 5 additions & 6 deletions src/interfaces/IPublicAllocator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ struct Withdrawal {
/// @dev This interface is used for factorizing IPublicAllocatorStaticTyping and IPublicAllocator.
/// @dev Consider using the IPublicAllocator interface instead of this one.
interface IPublicAllocatorBase {
/// @notice The address of the Morpho contract.
/// @notice The Morpho contract.
function MORPHO() external view returns (IMorpho);

/// @notice The address of the owner of the public allocator config for a given vault.
/// @dev The owner of the underlying vault always has the public allocator owner capabilities.
function owner(address vault) external view returns (address);
/// @notice The admin for a given vault.
function admin(address vault) external view returns (address);

/// @notice The current ETH fee for a given vault.
function fee(address vault) external view returns (uint256);
Expand All @@ -64,8 +63,8 @@ interface IPublicAllocatorBase {
external
payable;

/// @notice Sets the owner for a given vault.
function setOwner(address vault, address newOwner) external;
/// @notice Sets the admin for a given vault.
function setAdmin(address vault, address newAdmin) external;

/// @notice Sets the fee for a given vault.
function setFee(address vault, uint256 newFee) external;
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/ErrorsLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {Id} from "../../lib/metamorpho/src/interfaces/IMetaMorpho.sol";
/// @custom:contact security@morpho.org
/// @notice Library exposing error messages.
library ErrorsLib {
/// @notice Thrown when the `msg.sender` is not the `owner`.
error NotOwner();
/// @notice Thrown when the `msg.sender` is not the admin nor the owner of the vault.
error NotAdminNorVaultOwner();

/// @notice Thrown when the reallocation fee given is wrong.
error IncorrectFee();
Expand Down
10 changes: 5 additions & 5 deletions src/libraries/EventsLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ library EventsLib {
address indexed sender, address indexed vault, Id indexed supplyMarketId, uint256 suppliedAssets
);

/// @notice Emitted when the owner is set for a vault.
event SetOwner(address indexed sender, address indexed vault, address indexed owner);
/// @notice Emitted when the admin is set for a vault.
event SetAdmin(address indexed sender, address indexed vault, address admin);

/// @notice Emitted when the owner changes the `fee` for a vault.
/// @notice Emitted when the fee is set for a vault.
event SetFee(address indexed sender, address indexed vault, uint256 fee);

/// @notice Emitted when the owner transfers the fee for a vault.
/// @notice Emitted when the fee is transfered for a vault.
event TransferFee(address indexed sender, address indexed vault, uint256 amount, address indexed feeRecipient);

/// @notice Emitted when the owner updates some flow caps for a vault.
/// @notice Emitted when the flow caps are set for a vault.
event SetFlowCaps(address indexed sender, address indexed vault, FlowCapsConfig[] config);
}
111 changes: 98 additions & 13 deletions test/PublicAllocatorTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,40 @@ contract PublicAllocatorTest is IntegrationTest {
_sortSupplyQueueIdleLast();
}

function testOwner() public {
assertEq(publicAllocator.owner(address(vault)), address(0));
function testAdmin() public {
assertEq(publicAllocator.admin(address(vault)), address(0));
}

function testSetOwner() public {
function testSetAdmin() public {
vm.prank(OWNER);
publicAllocator.setOwner(address(vault), address(1));
assertEq(publicAllocator.owner(address(vault)), address(1));
publicAllocator.setAdmin(address(vault), address(1));
assertEq(publicAllocator.admin(address(vault)), address(1));
}

function testSetOwnerFail() public {
function testSetAdminByAdmin(address sender, address newAdmin) public {
vm.assume(publicAllocator.admin(address(vault)) != sender);
vm.assume(sender != newAdmin);
vm.prank(OWNER);
publicAllocator.setAdmin(address(vault), sender);
vm.prank(sender);
publicAllocator.setAdmin(address(vault), newAdmin);
assertEq(publicAllocator.admin(address(vault)), newAdmin);
}

function testSetAdminAlreadySet() public {
vm.expectRevert(ErrorsLib.AlreadySet.selector);
vm.prank(OWNER);
publicAllocator.setOwner(address(vault), address(0));
publicAllocator.setAdmin(address(vault), address(0));
}

function testSetAdminAccessFail(address sender, address newAdmin) public {
vm.assume(sender != OWNER);
vm.assume(publicAllocator.admin(address(vault)) != sender);
vm.assume(publicAllocator.admin(address(vault)) != newAdmin);

vm.expectRevert(ErrorsLib.NotAdminNorVaultOwner.selector);
vm.prank(sender);
publicAllocator.setAdmin(address(vault), newAdmin);
}

function testReallocateCapZeroOutflowByDefault(uint128 flow) public {
Expand All @@ -112,28 +132,28 @@ contract PublicAllocatorTest is IntegrationTest {

function testConfigureFlowAccessFail(address sender) public {
vm.assume(sender != OWNER);
vm.assume(sender != address(0));
vm.assume(publicAllocator.admin(address(vault)) != sender);

flowCaps.push(FlowCapsConfig(idleParams.id(), FlowCaps(0, 0)));

vm.prank(sender);
vm.expectRevert(ErrorsLib.NotOwner.selector);
vm.expectRevert(ErrorsLib.NotAdminNorVaultOwner.selector);
publicAllocator.setFlowCaps(address(vault), flowCaps);
}

function testTransferFeeAccessFail(address sender, address payable recipient) public {
vm.assume(sender != OWNER);
vm.assume(sender != address(0));
vm.assume(publicAllocator.admin(address(vault)) != sender);
vm.prank(sender);
vm.expectRevert(ErrorsLib.NotOwner.selector);
vm.expectRevert(ErrorsLib.NotAdminNorVaultOwner.selector);
publicAllocator.transferFee(address(vault), recipient);
}

function testSetFeeAccessFail(address sender, uint256 fee) public {
vm.assume(sender != OWNER);
vm.assume(sender != address(0));
vm.assume(publicAllocator.admin(address(vault)) != sender);
vm.prank(sender);
vm.expectRevert(ErrorsLib.NotOwner.selector);
vm.expectRevert(ErrorsLib.NotAdminNorVaultOwner.selector);
publicAllocator.setFee(address(vault), fee);
}

Expand All @@ -146,6 +166,18 @@ contract PublicAllocatorTest is IntegrationTest {
assertEq(publicAllocator.fee(address(vault)), fee);
}

function testSetFeeByAdmin(uint256 fee, address sender) public {
vm.assume(publicAllocator.admin(address(vault)) != sender);
vm.assume(fee != publicAllocator.fee(address(vault)));
vm.prank(OWNER);
publicAllocator.setAdmin(address(vault), sender);
vm.prank(sender);
vm.expectEmit(address(publicAllocator));
emit EventsLib.SetFee(sender, address(vault), fee);
publicAllocator.setFee(address(vault), fee);
assertEq(publicAllocator.fee(address(vault)), fee);
}

function testSetFeeAlreadySet(uint256 fee) public {
vm.assume(fee != publicAllocator.fee(address(vault)));
vm.prank(OWNER);
Expand Down Expand Up @@ -180,6 +212,35 @@ contract PublicAllocatorTest is IntegrationTest {
assertEq(flowCap.maxOut, out1);
}

function testSetFlowCapsByAdmin(uint128 in0, uint128 out0, uint128 in1, uint128 out1, address sender) public {
vm.assume(publicAllocator.admin(address(vault)) != sender);
in0 = uint128(bound(in0, 0, MAX_SETTABLE_FLOW_CAP));
out0 = uint128(bound(out0, 0, MAX_SETTABLE_FLOW_CAP));
in1 = uint128(bound(in1, 0, MAX_SETTABLE_FLOW_CAP));
out1 = uint128(bound(out1, 0, MAX_SETTABLE_FLOW_CAP));

flowCaps.push(FlowCapsConfig(idleParams.id(), FlowCaps(in0, out0)));
flowCaps.push(FlowCapsConfig(allMarkets[0].id(), FlowCaps(in1, out1)));

vm.prank(OWNER);
publicAllocator.setAdmin(address(vault), sender);

vm.expectEmit(address(publicAllocator));
emit EventsLib.SetFlowCaps(sender, address(vault), flowCaps);

vm.prank(sender);
publicAllocator.setFlowCaps(address(vault), flowCaps);

FlowCaps memory flowCap;
flowCap = publicAllocator.flowCaps(address(vault), idleParams.id());
assertEq(flowCap.maxIn, in0);
assertEq(flowCap.maxOut, out0);

flowCap = publicAllocator.flowCaps(address(vault), allMarkets[0].id());
assertEq(flowCap.maxIn, in1);
assertEq(flowCap.maxOut, out1);
}

function testPublicReallocateEvent(uint128 flow, address sender) public {
flow = uint128(bound(flow, 1, CAP2 / 2));

Expand Down Expand Up @@ -298,6 +359,30 @@ contract PublicAllocatorTest is IntegrationTest {
assertEq(address(this).balance - before, 2 * 0.001 ether, "wrong fee transferred");
}

function testTransferFeeByAdminSuccess(address sender) public {
vm.assume(publicAllocator.admin(address(vault)) != sender);
vm.prank(OWNER);
publicAllocator.setAdmin(address(vault), sender);
vm.prank(sender);
publicAllocator.setFee(address(vault), 0.001 ether);

flowCaps.push(FlowCapsConfig(idleParams.id(), FlowCaps(0, 2 ether)));
flowCaps.push(FlowCapsConfig(allMarkets[0].id(), FlowCaps(2 ether, 0)));
vm.prank(OWNER);
publicAllocator.setFlowCaps(address(vault), flowCaps);
withdrawals.push(Withdrawal(idleParams, 1 ether));

publicAllocator.reallocateTo{value: 0.001 ether}(address(vault), withdrawals, allMarkets[0]);
publicAllocator.reallocateTo{value: 0.001 ether}(address(vault), withdrawals, allMarkets[0]);

uint256 before = address(this).balance;

vm.prank(sender);
publicAllocator.transferFee(address(vault), payable(address(this)));

assertEq(address(this).balance - before, 2 * 0.001 ether, "wrong fee transferred");
}

function testTransferFeeFail() public {
vm.prank(OWNER);
publicAllocator.setFee(address(vault), 0.001 ether);
Expand Down

0 comments on commit 14f37ed

Please sign in to comment.