Skip to content
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ DssExecLib.setChangelogAddress("MCD_CLIP_CALC_XMPL-A", xmpl_calc);

- `executeStarSpell(address _starProxy, address _starSpell)`: Execute a star spell through its star proxy. Returns the return data from the spell execution.
- `tryExecuteStarSpell(address _starProxy, address _starSpell)`: Tries to execute a star spell through its star proxy using low-level call to avoid reverts in case of error. Returns a boolean indicating success and the return data or error message.
- `plotStarSpell(address _starGuard, address _starSpell, bytes32 _starSpellTag)`: Whitelist a star spell in its star guard so it can be executed permissionlessly. `_starSpellTag` is the expected codehash of the star spell.
- `dropStarSpell(address _starGuard)`: Remove the currently whitelisted star spell from the star guard.

### Misc

Expand Down
74 changes: 74 additions & 0 deletions src/DssAction.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {MockToken} from "./mocks/MockToken.sol";
import {MockValue} from "./mocks/MockValue.sol";
import {MockOracle} from "./mocks/MockOracle.sol";
import {MockOsm} from "./mocks/MockOsm.sol";
import {MockStarGuard} from "./mocks/MockStarGuard.sol";
import {MockStarProxy} from "./mocks/MockStarProxy.sol";
import {MockStarSpell} from "./mocks/MockStarSpell.sol";

Expand Down Expand Up @@ -1328,4 +1329,77 @@ contract DssActionTest is Test {
// Verify the spell was not executed
assertFalse(proxy.executed(), "Spell should not have been executed when configured to fail");
}

function test_plotStarSpell_success() public {
Comment thread
riccardopersiani marked this conversation as resolved.
// Setup mock contract and spell parameters
MockStarGuard guard = new MockStarGuard();
address starSpell = address(0xBEEF);
bytes32 starSpellTag = keccak256("some-bytecode");

// Plot the spell on the guard
action.plotStarSpell_test(address(guard), starSpell, starSpellTag);

// Verify the guard recorded the correct spell address and tag
assertEq(guard.plottedAddr(), starSpell, "StarGuard should have recorded the plotted spell");
assertEq(guard.plottedTag(), starSpellTag, "StarGuard should have recorded the plotted tag");
}

function test_plotStarSpell_overwritesPreviousPlot() public {
// Setup mock contract and two distinct spell parameters
MockStarGuard guard = new MockStarGuard();
address firstSpell = address(0xBEEF);
bytes32 firstTag = keccak256("first-bytecode");
address secondSpell = address(0xCAFE);
bytes32 secondTag = keccak256("second-bytecode");

// Plot the first spell, then plot the second spell on top of it
action.plotStarSpell_test(address(guard), firstSpell, firstTag);
action.plotStarSpell_test(address(guard), secondSpell, secondTag);

// Verify the guard now reflects the second spell, overwriting the first
assertEq(guard.plottedAddr(), secondSpell, "StarGuard should overwrite the plotted spell");
assertEq(guard.plottedTag(), secondTag, "StarGuard should overwrite the plotted tag");
}

function test_plotStarSpell_failure() public {
// Setup mock contract
MockStarGuard guard = new MockStarGuard();

// Configure the guard to fail
guard.setShouldFail(true);

// This should revert
vm.expectRevert("MockStarGuard/plot-failed");
action.plotStarSpell_test(address(guard), address(0xBEEF), bytes32(uint256(1)));
}

function test_dropStarSpell_success() public {
// Setup mock contract and spell parameters
MockStarGuard guard = new MockStarGuard();
address starSpell = address(0xBEEF);
bytes32 starSpellTag = keccak256("some-bytecode");

// Plot a spell so we have something to drop
action.plotStarSpell_test(address(guard), starSpell, starSpellTag);
assertEq(guard.plottedAddr(), starSpell, "Precondition: spell should be plotted");

// Drop the plotted spell
action.dropStarSpell_test(address(guard));

// Verify the guard cleared its recorded spell address and tag
assertEq(guard.plottedAddr(), address(0), "StarGuard should have cleared the plotted spell");
assertEq(guard.plottedTag(), bytes32(0), "StarGuard should have cleared the plotted tag");
}

function test_dropStarSpell_failure() public {
// Setup mock contract
MockStarGuard guard = new MockStarGuard();

// Configure the guard to fail
guard.setShouldFail(true);

// This should revert
vm.expectRevert("MockStarGuard/drop-failed");
action.dropStarSpell_test(address(guard));
}
}
19 changes: 19 additions & 0 deletions src/DssExecLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ interface ProxyLike {
function exec(address target, bytes calldata args) external payable returns (bytes memory out);
}

interface StarGuardLike {
function plot(address addr_, bytes32 tag_) external;
function drop() external;
}

/// @title DssExecLib - Sky Protocol's Executive Spellcrafting Library
/// @notice This library provides a suite of functions for managing the Sky Protocol.
/// @dev Includes functions for collateral management, system configuration, governance, and more.
Expand Down Expand Up @@ -1197,4 +1202,18 @@ library DssExecLib {

return (success, result);
}

/// @dev Whitelist a star spell in the corresponding star guard to enable permissionless execution.
/// @param _starGuard The star guard contract that gates the star spell.
/// @param _starSpell The address of the star spell to whitelist.
/// @param _starSpellTag The expected codehash of the star spell.
function plotStarSpell(address _starGuard, address _starSpell, bytes32 _starSpellTag) public {
StarGuardLike(_starGuard).plot(_starSpell, _starSpellTag);
}

/// @dev Remove the currently whitelisted star spell from a star guard.
Comment thread
amusingaxl marked this conversation as resolved.
/// @param _starGuard The star guard contract that gates the star spell.
function dropStarSpell(address _starGuard) public {
StarGuardLike(_starGuard).drop();
}
}
8 changes: 8 additions & 0 deletions src/mocks/MockDssSpellAction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,12 @@ contract MockDssSpellAction is DssAction {
function tryExecuteStarSpell_test(address starProxy, address starSpell) public returns (bool, bytes memory) {
return DssExecLib.tryExecuteStarSpell(starProxy, starSpell);
}

function plotStarSpell_test(address starGuard, address starSpell, bytes32 starSpellTag) public {
DssExecLib.plotStarSpell(starGuard, starSpell, starSpellTag);
}

function dropStarSpell_test(address starGuard) public {
DssExecLib.dropStarSpell(starGuard);
}
}
42 changes: 42 additions & 0 deletions src/mocks/MockStarGuard.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// MockStarGuard.sol -- Mock Star Guard for testing
//
// Copyright (C) 2022-2026 Dai Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.16;

contract MockStarGuard {
address public plottedAddr;
bytes32 public plottedTag;
bool public shouldFail;

function setShouldFail(bool _shouldFail) external {
shouldFail = _shouldFail;
}

function plot(address addr_, bytes32 tag_) external {
require(!shouldFail, "MockStarGuard/plot-failed");
plottedAddr = addr_;
plottedTag = tag_;
}

function drop() external {
require(!shouldFail, "MockStarGuard/drop-failed");
plottedAddr = address(0);
plottedTag = bytes32(0);
}
}
Loading