diff --git a/src/interfaces/IOwnable.sol b/src/interfaces/IOwnable.sol new file mode 100644 index 000000000..0169b6810 --- /dev/null +++ b/src/interfaces/IOwnable.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: LicenseRef-BUSL +pragma solidity ^0.8.0; + +/// @title IOwnable +/// @author Aave Labs +/// @notice Interface for contracts exposing Ownable access control. +interface IOwnable { + /// @notice Returns the address of the current owner. + function owner() external view returns (address); +} diff --git a/src/spoke/TreasurySpoke.sol b/src/spoke/TreasurySpoke.sol index e617e573f..e8f8108bc 100644 --- a/src/spoke/TreasurySpoke.sol +++ b/src/spoke/TreasurySpoke.sol @@ -2,7 +2,9 @@ pragma solidity 0.8.28; import {Ownable2StepUpgradeable} from 'src/dependencies/openzeppelin-upgradeable/Ownable2StepUpgradeable.sol'; +import {OwnableUpgradeable} from 'src/dependencies/openzeppelin-upgradeable/OwnableUpgradeable.sol'; import {SafeERC20, IERC20} from 'src/dependencies/openzeppelin/SafeERC20.sol'; +import {IOwnable} from 'src/interfaces/IOwnable.sol'; import {MathUtils} from 'src/libraries/math/MathUtils.sol'; import {IHubBase} from 'src/hub/interfaces/IHubBase.sol'; import {ITreasurySpoke} from 'src/spoke/interfaces/ITreasurySpoke.sol'; @@ -18,6 +20,11 @@ abstract contract TreasurySpoke is ITreasurySpoke, Ownable2StepUpgradeable { /// @dev To be overridden by the inheriting TreasurySpoke instance contract. function initialize(address owner) external virtual; + /// @inheritdoc IOwnable + function owner() public view virtual override(IOwnable, OwnableUpgradeable) returns (address) { + return super.owner(); + } + /// @inheritdoc ITreasurySpoke function supply( address hub, diff --git a/src/spoke/interfaces/ITreasurySpoke.sol b/src/spoke/interfaces/ITreasurySpoke.sol index 30ef548c8..8e8082e04 100644 --- a/src/spoke/interfaces/ITreasurySpoke.sol +++ b/src/spoke/interfaces/ITreasurySpoke.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: LicenseRef-BUSL pragma solidity ^0.8.0; +import {IOwnable} from 'src/interfaces/IOwnable.sol'; + /// @title ITreasurySpoke /// @author Aave Labs /// @notice Interface for the TreasurySpoke. -interface ITreasurySpoke { +interface ITreasurySpoke is IOwnable { /// @notice Supplies a specified amount of the underlying asset to the specified Hub. /// @dev The Spoke pulls the underlying asset from the caller, so prior approval is required. /// @param hub The address of the Hub. diff --git a/tests/contracts/treasury-spoke/TreasurySpoke.t.sol b/tests/contracts/treasury-spoke/TreasurySpoke.t.sol index c97e108d8..28c1be72e 100644 --- a/tests/contracts/treasury-spoke/TreasurySpoke.t.sol +++ b/tests/contracts/treasury-spoke/TreasurySpoke.t.sol @@ -71,6 +71,7 @@ contract TreasurySpokeTest is Base { assertEq(treasurySpoke.getSuppliedShares(address(hub2), underlying), 0); } assertEq(Ownable2Step(address(treasurySpoke)).owner(), TREASURY_ADMIN); + assertEq(treasurySpoke.owner(), TREASURY_ADMIN); assertEq(Ownable2Step(address(treasurySpoke)).pendingOwner(), address(0)); }