From c20570ba1bc44f035b65f6d1b78609dee3b0e8f7 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 5 Jul 2023 11:56:20 +0200 Subject: [PATCH 1/8] feat: add owner to contract --- src/Blue.sol | 6 +++++- src/dependencies/Owned.sol | 44 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/dependencies/Owned.sol diff --git a/src/Blue.sol b/src/Blue.sol index 50dee219d..306e93435 100644 --- a/src/Blue.sol +++ b/src/Blue.sol @@ -7,6 +7,8 @@ import {IOracle} from "src/interfaces/IOracle.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {SafeTransferLib} from "src/libraries/SafeTransferLib.sol"; +import {Owned} from "src/dependencies/Owned.sol"; + uint constant WAD = 1e18; uint constant alpha = 0.5e18; @@ -29,7 +31,7 @@ function irm(uint utilization) pure returns (uint) { return utilization / 365 days; } -contract Blue { +contract Blue is Owned { using MathLib for uint; using SafeTransferLib for IERC20; @@ -52,6 +54,8 @@ contract Blue { // Interests last update (used to check if a market has been created). mapping(Id => uint) public lastUpdate; + constructor(address owner) Owned(owner) {} + // Markets management. function createMarket(Market calldata market) external { diff --git a/src/dependencies/Owned.sol b/src/dependencies/Owned.sol new file mode 100644 index 000000000..e82b44d83 --- /dev/null +++ b/src/dependencies/Owned.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Simple single owner authorization mixin. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) +abstract contract Owned { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event OwnershipTransferred(address indexed user, address indexed newOwner); + + /*////////////////////////////////////////////////////////////// + OWNERSHIP STORAGE + //////////////////////////////////////////////////////////////*/ + + address public owner; + + modifier onlyOwner() virtual { + require(msg.sender == owner, "UNAUTHORIZED"); + + _; + } + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(address _owner) { + owner = _owner; + + emit OwnershipTransferred(address(0), _owner); + } + + /*////////////////////////////////////////////////////////////// + OWNERSHIP LOGIC + //////////////////////////////////////////////////////////////*/ + + function transferOwnership(address newOwner) public virtual onlyOwner { + owner = newOwner; + + emit OwnershipTransferred(msg.sender, newOwner); + } +} From f877eb5587a10d87c5003ef7a9a43f0d8752dbd5 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 5 Jul 2023 12:34:38 +0200 Subject: [PATCH 2/8] fix: deployment --- test/forge/Blue.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index d814c7f97..b1ab80dc6 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -28,7 +28,7 @@ contract BlueTest is Test { function setUp() public { // Create Blue. - blue = new Blue(); + blue = new Blue(msg.sender); // List a market. borrowableAsset = new ERC20("borrowable", "B", 18); From 05b8db618b9e8fedd9da6597b957ff26c8271fd3 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 5 Jul 2023 15:24:18 +0200 Subject: [PATCH 3/8] feat: update file --- src/Blue.sol | 6 +++--- src/Ownable.sol | 39 +++++++++++++++++++++++++++++++++ src/dependencies/Owned.sol | 44 -------------------------------------- 3 files changed, 42 insertions(+), 47 deletions(-) create mode 100644 src/Ownable.sol delete mode 100644 src/dependencies/Owned.sol diff --git a/src/Blue.sol b/src/Blue.sol index 306e93435..834fe13b2 100644 --- a/src/Blue.sol +++ b/src/Blue.sol @@ -7,7 +7,7 @@ import {IOracle} from "src/interfaces/IOracle.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {SafeTransferLib} from "src/libraries/SafeTransferLib.sol"; -import {Owned} from "src/dependencies/Owned.sol"; +import {Ownable} from "src/Ownable.sol"; uint constant WAD = 1e18; @@ -31,7 +31,7 @@ function irm(uint utilization) pure returns (uint) { return utilization / 365 days; } -contract Blue is Owned { +contract Blue is Ownable { using MathLib for uint; using SafeTransferLib for IERC20; @@ -54,7 +54,7 @@ contract Blue is Owned { // Interests last update (used to check if a market has been created). mapping(Id => uint) public lastUpdate; - constructor(address owner) Owned(owner) {} + constructor(address owner) Ownable(owner) {} // Markets management. diff --git a/src/Ownable.sol b/src/Ownable.sol new file mode 100644 index 000000000..f664124b4 --- /dev/null +++ b/src/Ownable.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @title Ownable +/// @author Morpho Labs +/// @custom:contact security@morpho.xyz +/// @dev Greatly inspired by Solmate and OZ implementations. +abstract contract Ownable { + /* EVENTS */ + + event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); + + /* STORAGE */ + + address public owner; + + /* MODIFIERS */ + + modifier onlyOwner() virtual { + require(msg.sender == owner, "not owner"); + _; + } + + /* CONSTRUCTOR */ + + constructor(address newOwner) { + owner = newOwner; + + emit OwnershipTransferred(address(0), newOwner); + } + + /* PUBLIC */ + + function transferOwnership(address newOwner) public virtual onlyOwner { + owner = newOwner; + + emit OwnershipTransferred(msg.sender, newOwner); + } +} diff --git a/src/dependencies/Owned.sol b/src/dependencies/Owned.sol deleted file mode 100644 index e82b44d83..000000000 --- a/src/dependencies/Owned.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0; - -/// @notice Simple single owner authorization mixin. -/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) -abstract contract Owned { - /*////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////*/ - - event OwnershipTransferred(address indexed user, address indexed newOwner); - - /*////////////////////////////////////////////////////////////// - OWNERSHIP STORAGE - //////////////////////////////////////////////////////////////*/ - - address public owner; - - modifier onlyOwner() virtual { - require(msg.sender == owner, "UNAUTHORIZED"); - - _; - } - - /*////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////*/ - - constructor(address _owner) { - owner = _owner; - - emit OwnershipTransferred(address(0), _owner); - } - - /*////////////////////////////////////////////////////////////// - OWNERSHIP LOGIC - //////////////////////////////////////////////////////////////*/ - - function transferOwnership(address newOwner) public virtual onlyOwner { - owner = newOwner; - - emit OwnershipTransferred(msg.sender, newOwner); - } -} From 70cb8b026c3a27a4bc7aa78fbc27b72db804a70e Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 5 Jul 2023 15:27:39 +0200 Subject: [PATCH 4/8] test: add test owner --- test/forge/Blue.t.sol | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/forge/Blue.t.sol b/test/forge/Blue.t.sol index b1ab80dc6..e31bbd849 100644 --- a/test/forge/Blue.t.sol +++ b/test/forge/Blue.t.sol @@ -91,6 +91,30 @@ contract BlueTest is Test { // Tests + function testOwner(address owner) public { + Blue blue2 = new Blue(owner); + + assertEq(blue2.owner(), owner, "owner"); + } + + function testTransferOwnership(address oldOwner, address newOwner) public { + Blue blue2 = new Blue(oldOwner); + + vm.prank(oldOwner); + blue2.transferOwnership(newOwner); + assertEq(blue2.owner(), newOwner, "owner"); + } + + function testTransferOwnershipWhenNotOwner(address attacker, address newOwner) public { + vm.assume(attacker != address(0xdead)); + + Blue blue2 = new Blue(address(0xdead)); + + vm.prank(attacker); + vm.expectRevert("not owner"); + blue2.transferOwnership(newOwner); + } + function testSupply(uint amount) public { amount = bound(amount, 1, 2 ** 64); From 88ccfb94bb6d44c266e2bfcda7300aeba3c1c523 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Thu, 6 Jul 2023 08:02:02 +0200 Subject: [PATCH 5/8] refactor: remove event --- src/Ownable.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Ownable.sol b/src/Ownable.sol index f664124b4..0d226345e 100644 --- a/src/Ownable.sol +++ b/src/Ownable.sol @@ -6,10 +6,6 @@ pragma solidity >=0.8.0; /// @custom:contact security@morpho.xyz /// @dev Greatly inspired by Solmate and OZ implementations. abstract contract Ownable { - /* EVENTS */ - - event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); - /* STORAGE */ address public owner; From 06d5441cdf268cebb29525e65a5efa148cb7d0ba Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Thu, 6 Jul 2023 08:11:30 +0200 Subject: [PATCH 6/8] fix: removal --- src/Ownable.sol | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Ownable.sol b/src/Ownable.sol index 0d226345e..6dfee241c 100644 --- a/src/Ownable.sol +++ b/src/Ownable.sol @@ -21,15 +21,11 @@ abstract contract Ownable { constructor(address newOwner) { owner = newOwner; - - emit OwnershipTransferred(address(0), newOwner); } /* PUBLIC */ function transferOwnership(address newOwner) public virtual onlyOwner { owner = newOwner; - - emit OwnershipTransferred(msg.sender, newOwner); } } From ad03870d98190c4ec0dab43edac974a797d42bf1 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Thu, 6 Jul 2023 10:55:45 +0200 Subject: [PATCH 7/8] feat: implement suggestions --- src/Ownable.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Ownable.sol b/src/Ownable.sol index 6dfee241c..ff1484e35 100644 --- a/src/Ownable.sol +++ b/src/Ownable.sol @@ -1,5 +1,5 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity >=0.8.0; +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.20; /// @title Ownable /// @author Morpho Labs @@ -12,7 +12,7 @@ abstract contract Ownable { /* MODIFIERS */ - modifier onlyOwner() virtual { + modifier onlyOwner() { require(msg.sender == owner, "not owner"); _; } @@ -25,7 +25,7 @@ abstract contract Ownable { /* PUBLIC */ - function transferOwnership(address newOwner) public virtual onlyOwner { + function transferOwnership(address newOwner) external onlyOwner { owner = newOwner; } } From d36f6a019603e6b1ecdc227f3614d008d8289641 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Thu, 6 Jul 2023 16:19:44 +0200 Subject: [PATCH 8/8] feat: internalize owner --- src/Blue.sol | 25 +++++++++++++++++++++---- src/Ownable.sol | 31 ------------------------------- 2 files changed, 21 insertions(+), 35 deletions(-) delete mode 100644 src/Ownable.sol diff --git a/src/Blue.sol b/src/Blue.sol index 834fe13b2..3be894499 100644 --- a/src/Blue.sol +++ b/src/Blue.sol @@ -7,8 +7,6 @@ import {IOracle} from "src/interfaces/IOracle.sol"; import {MathLib} from "src/libraries/MathLib.sol"; import {SafeTransferLib} from "src/libraries/SafeTransferLib.sol"; -import {Ownable} from "src/Ownable.sol"; - uint constant WAD = 1e18; uint constant alpha = 0.5e18; @@ -31,12 +29,14 @@ function irm(uint utilization) pure returns (uint) { return utilization / 365 days; } -contract Blue is Ownable { +contract Blue { using MathLib for uint; using SafeTransferLib for IERC20; // Storage. + // Owner. + address public owner; // User' supply balances. mapping(Id => mapping(address => uint)) public supplyShare; // User' borrow balances. @@ -54,7 +54,24 @@ contract Blue is Ownable { // Interests last update (used to check if a market has been created). mapping(Id => uint) public lastUpdate; - constructor(address owner) Ownable(owner) {} + // Constructor. + + constructor(address newOwner) { + owner = newOwner; + } + + // Modifiers. + + modifier onlyOwner() { + require(msg.sender == owner, "not owner"); + _; + } + + // Only owner functions. + + function transferOwnership(address newOwner) external onlyOwner { + owner = newOwner; + } // Markets management. diff --git a/src/Ownable.sol b/src/Ownable.sol deleted file mode 100644 index ff1484e35..000000000 --- a/src/Ownable.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.20; - -/// @title Ownable -/// @author Morpho Labs -/// @custom:contact security@morpho.xyz -/// @dev Greatly inspired by Solmate and OZ implementations. -abstract contract Ownable { - /* STORAGE */ - - address public owner; - - /* MODIFIERS */ - - modifier onlyOwner() { - require(msg.sender == owner, "not owner"); - _; - } - - /* CONSTRUCTOR */ - - constructor(address newOwner) { - owner = newOwner; - } - - /* PUBLIC */ - - function transferOwnership(address newOwner) external onlyOwner { - owner = newOwner; - } -}