diff --git a/src/SparkLendFreezerMom.sol b/src/SparkLendFreezerMom.sol index bfeccac..12e89a3 100644 --- a/src/SparkLendFreezerMom.sol +++ b/src/SparkLendFreezerMom.sol @@ -21,6 +21,8 @@ contract SparkLendFreezerMom is ISparkLendFreezerMom { address public override authority; address public override owner; + + mapping(address => uint256) public override wards; constructor(address poolConfigurator_, address pool_) { poolConfigurator = poolConfigurator_; @@ -59,6 +61,16 @@ contract SparkLendFreezerMom is ISparkLendFreezerMom { owner = owner_; } + function rely(address usr) external override onlyOwner { + wards[usr] = 1; + emit Rely(usr); + } + + function deny(address usr) external override onlyOwner { + wards[usr] = 0; + emit Deny(usr); + } + /**********************************************************************************************/ /*** Auth Functions ***/ /**********************************************************************************************/ @@ -100,7 +112,7 @@ contract SparkLendFreezerMom is ISparkLendFreezerMom { function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == address(this)) { return true; - } else if (src == owner) { + } else if (src == owner || wards[src] == 1) { return true; } else if (authority == address(0)) { return false; diff --git a/src/interfaces/ISparkLendFreezerMom.sol b/src/interfaces/ISparkLendFreezerMom.sol index 4c559f4..65defb0 100644 --- a/src/interfaces/ISparkLendFreezerMom.sol +++ b/src/interfaces/ISparkLendFreezerMom.sol @@ -37,6 +37,18 @@ interface ISparkLendFreezerMom { */ event SetAuthority(address indexed oldAuthority, address indexed newAuthority); + /** + * @dev Authorize a contract to trigger this mom. + * @param usr The address to authorize. + */ + event Rely(address indexed usr); + + /** + * @dev Deauthorize a contract to trigger this mom. + * @param usr The address to deauthorize. + */ + event Deny(address indexed usr); + /**********************************************************************************************/ /*** Storage Variables ***/ /**********************************************************************************************/ @@ -65,6 +77,12 @@ interface ISparkLendFreezerMom { */ function owner() external view returns (address); + /** + * @dev Returns if an address is authroized to trigger this mom (or not). + * @return 1 if authorized, 0 if not. + */ + function wards(address usr) external view returns (uint256); + /**********************************************************************************************/ /*** Owner Functions ***/ /**********************************************************************************************/ @@ -81,6 +99,18 @@ interface ISparkLendFreezerMom { */ function setOwner(address owner) external; + /** + * @dev Authorize a contract to trigger this mom. + * @param usr The address to authorize. + */ + function rely(address usr) external; + + /** + * @dev Deauthorize a contract to trigger this mom. + * @param usr The address to deauthorize. + */ + function deny(address usr) external; + /**********************************************************************************************/ /*** Auth Functions ***/ /**********************************************************************************************/ diff --git a/test/SparkLendFreezerMom.t.sol b/test/SparkLendFreezerMom.t.sol index 1e40663..7d1f6f7 100644 --- a/test/SparkLendFreezerMom.t.sol +++ b/test/SparkLendFreezerMom.t.sol @@ -83,6 +83,48 @@ contract SetAuthorityTests is SparkLendFreezerMomUnitTestBase { } +contract RelyTests is SparkLendFreezerMomUnitTestBase { + + function test_rely_noAuth() public { + vm.expectRevert("SparkLendFreezerMom/only-owner"); + freezer.rely(makeAddr("authedContract")); + } + + function test_rely() public { + address authedContract = makeAddr("authedContract"); + assertEq(freezer.wards(authedContract), 0); + + vm.prank(owner); + freezer.rely(authedContract); + + assertEq(freezer.wards(authedContract), 1); + } + +} + +contract DenyTests is SparkLendFreezerMomUnitTestBase { + + function test_deny_noAuth() public { + vm.expectRevert("SparkLendFreezerMom/only-owner"); + freezer.deny(makeAddr("authedContract")); + } + + function test_deny() public { + address authedContract = makeAddr("authedContract"); + + vm.prank(owner); + freezer.rely(authedContract); + + assertEq(freezer.wards(authedContract), 1); + + vm.prank(owner); + freezer.deny(authedContract); + + assertEq(freezer.wards(authedContract), 0); + } + +} + contract FreezeAllMarketsTests is SparkLendFreezerMomUnitTestBase { function test_freezeAllMarkets_noAuth() public { @@ -242,6 +284,7 @@ contract SparkLendFreezerMomIsAuthorizedTest is Test { address public configurator; address public pool; address public owner; + address public authedContract; AuthorityMock public authority; @@ -250,13 +293,15 @@ contract SparkLendFreezerMomIsAuthorizedTest is Test { address caller = makeAddr("caller"); function setUp() public { - owner = makeAddr("owner"); + owner = makeAddr("owner"); + authedContract = makeAddr("authedContract"); authority = new AuthorityMock(); configurator = address(new ConfiguratorMock()); pool = address(new PoolMock()); freezer = new SparkLendFreezerMomHarness(configurator, pool); + freezer.rely(authedContract); freezer.setAuthority(address(authority)); freezer.setOwner(owner); } @@ -269,6 +314,10 @@ contract SparkLendFreezerMomIsAuthorizedTest is Test { assertEq(freezer.isAuthorizedExternal(owner, bytes4("0")), true); } + function test_isAuthorized_srcIsWard() external { + assertEq(freezer.isAuthorizedExternal(authedContract, bytes4("0")), true); + } + function test_isAuthorized_authorityIsZero() external { vm.prank(owner); freezer.setAuthority(address(0)); @@ -297,6 +346,8 @@ contract EventTests is SparkLendFreezerMomUnitTestBase { event PauseMarket(address indexed reserve, bool pause); event SetOwner(address indexed oldOwner, address indexed newOwner); event SetAuthority(address indexed oldAuthority, address indexed newAuthority); + event Rely(address indexed usr); + event Deny(address indexed usr); function test_setAuthority_eventData() external { address newAuthority = makeAddr("newAuthority"); @@ -316,6 +367,24 @@ contract EventTests is SparkLendFreezerMomUnitTestBase { freezer.setOwner(newOwner); } + function test_rely_eventData() external { + address authedContract = makeAddr("authedContract"); + + vm.prank(owner); + vm.expectEmit(address(freezer)); + emit Rely(authedContract); + freezer.rely(authedContract); + } + + function test_deny_eventData() external { + address authedContract = makeAddr("authedContract"); + + vm.prank(owner); + vm.expectEmit(address(freezer)); + emit Deny(authedContract); + freezer.deny(authedContract); + } + function test_freezeMarket_eventData() public { address caller = makeAddr("caller"); address asset = makeAddr("asset");