Skip to content

Commit d8d3aec

Browse files
Modify officeHours to be in action (#36)
1 parent 794f323 commit d8d3aec

File tree

8 files changed

+57
-40
lines changed

8 files changed

+57
-40
lines changed

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,11 @@ import {DssAction} from "lib/dss-exec-lib/src/DssAction.sol";
2323

2424
contract SpellAction is DssAction {
2525

26-
// This can be hardcoded away later or can use the chain-log
27-
constructor(address lib) DssAction(lib) public {}
26+
constructor(address lib, bool officeHours) DssAction(lib, officeHours) public {}
2827

2928
uint256 constant MILLION = 10 ** 6;
3029

31-
function execute() external {
30+
function actions() public override {
3231
setGlobalDebtCeiling(1500 * MILLION);
3332
setIlkDebtCeiling("ETH-A", 10 * MILLION);
3433
}
@@ -37,13 +36,16 @@ contract SpellAction is DssAction {
3736

3837
The `SpellAction.sol` file must always inherit `DssAction` from `lib/dss-exec-lib`.
3938

39+
The developer must override the `actions()` function and place all spell actions within. This is called by the `execute()` function in the pause, which is subject to an optional limiter for office hours.
40+
41+
*Note:* All variables within the SpellAction MUST be defined as constants, or assigned at runtime inside of the `actions()` function. Variable memory storage is not available within a Spell Action due to the underlying delegatecall mechanisms.
42+
4043
The spell itself is deployed as follows:
4144

4245
```js
4346
new DssExec(
4447
"A test dss exec spell", // Description
4548
now + 30 days, // Expiration
46-
true, // OfficeHours enabled
4749
address(new SpellAction(execlib))
4850
);
4951
```
@@ -158,7 +160,7 @@ CollateralOpts memory XMPL_A = CollateralOpts({
158160
gem: 0xCE4F3774620764Ea881a8F8840Cbe0F701372283,
159161
join: 0xa30925910067a2d9eB2a7358c017E6075F660842,
160162
flip: 0x32c6DF17f8E94694977aa41A595d8dc583836A51,
161-
pip: 0x9eb923339c24c40Bef2f4AF4961742AA7C23EF3a,
163+
pip: 0x9eb923339c24c40Bef2f4AF4961742AA7C23EF3a,
162164
isLiquidatable: true,
163165
isOSM: true,
164166
whitelistOSM: true,

src/DssAction.sol

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,39 @@ interface OracleLike {
5252
function diss(address[] calldata) external;
5353
}
5454

55-
contract DssAction {
55+
abstract contract DssAction {
5656

5757
address public immutable lib;
58+
bool public immutable officeHours;
5859

5960
// Changelog address applies to MCD deployments on
6061
// mainnet, kovan, rinkeby, ropsten, and goerli
6162
address constant public LOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F;
6263

63-
constructor(address lib_) public {
64+
constructor(address lib_, bool officeHours_) public {
6465
lib = lib_;
66+
officeHours = officeHours_;
67+
}
68+
69+
// DssExec calls execute. We limit this function subject to officeHours modifier.
70+
function execute() external limited {
71+
actions();
72+
}
73+
74+
// DssAction developer must override `actions()` and place all actions to be called inside.
75+
// The DssExec function will call this subject to the officeHours limiter
76+
// By keeping this function public we allow simulations of `execute()` on the actions outside of the cast time.
77+
function actions() public virtual;
78+
79+
// Modifier required to
80+
modifier limited {
81+
if (officeHours) {
82+
uint day = (block.timestamp / 1 days + 3) % 7;
83+
require(day < 5, "Can only be cast on a weekday");
84+
uint hour = block.timestamp / 1 hours % 24;
85+
require(hour >= 14 && hour < 21, "Outside office hours");
86+
}
87+
_;
6588
}
6689

6790
/****************************/

src/DssExec.sol

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ interface Changelog {
2929
function getAddress(bytes32) external view returns (address);
3030
}
3131

32+
interface SpellAction {
33+
function officeHours() external view returns (bool);
34+
}
35+
3236
contract DssExec {
3337

3438
Changelog constant public log = Changelog(0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F);
@@ -38,23 +42,24 @@ contract DssExec {
3842
bytes32 immutable public tag;
3943
address immutable public action;
4044
uint256 immutable public expiration;
41-
bool immutable public officeHours;
4245
PauseAbstract immutable public pause;
4346

4447
// Provides a descriptive tag for bot consumption
4548
// This should be modified weekly to provide a summary of the actions
4649
// Hash: seth keccak -- "$(wget https://<executive-vote-canonical-post> -q -O - 2>/dev/null)"
4750
string public description;
4851

52+
function officeHours() external view returns (bool) {
53+
return SpellAction(action).officeHours();
54+
}
55+
4956
// @param _description A string description of the spell
5057
// @param _expiration The timestamp this spell will expire. (Ex. now + 30 days)
51-
// @param _officeHours Limits the executive cast time to office hours (true for limit)
5258
// @param _spellAction The address of the spell action
53-
constructor(string memory _description, uint256 _expiration, bool _officeHours, address _spellAction) public {
59+
constructor(string memory _description, uint256 _expiration, address _spellAction) public {
5460
pause = PauseAbstract(log.getAddress("MCD_PAUSE"));
5561
description = _description;
5662
expiration = _expiration;
57-
officeHours = _officeHours;
5863
action = _spellAction;
5964

6065
sig = abi.encodeWithSignature("execute()");
@@ -64,24 +69,14 @@ contract DssExec {
6469
tag = _tag;
6570
}
6671

67-
modifier limited {
68-
if(officeHours) {
69-
uint day = (now / 1 days + 3) % 7;
70-
require(day < 5, "Can only be cast on a weekday");
71-
uint hour = now / 1 hours % 24;
72-
require(hour >= 14 && hour < 21, "Outside office hours");
73-
}
74-
_;
75-
}
76-
7772
function schedule() public {
7873
require(now <= expiration, "This contract has expired");
7974
require(eta == 0, "This spell has already been scheduled");
8075
eta = now + PauseAbstract(pause).delay();
8176
pause.plot(action, tag, sig, eta);
8277
}
8378

84-
function cast() limited public {
79+
function cast() public {
8580
require(!done, "spell-already-cast");
8681
done = true;
8782
pause.exec(action, tag, sig, eta);

src/DssExecFactory.sol

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,16 @@ contract DssExecFactory {
2626
//
2727
// @param description A string description of the spell
2828
// @param expiration The timestamp this spell will expire. (Ex. now + 30 days)
29-
// @param officeHours Limits the executive cast time to office hours (true for limit)
3029
// @param spellAction The address of the spell action contract (DssAction)
31-
function newExec(string memory description, uint256 expiration, bool officeHours, address spellAction) public returns (address exec) {
32-
exec = address(new DssExec(description, expiration, officeHours, spellAction));
30+
function newExec(string memory description, uint256 expiration, address spellAction) public returns (address exec) {
31+
exec = address(new DssExec(description, expiration, spellAction));
3332
}
3433

3534
function newWeeklyExec(string memory description, address spellAction) public returns (address exec) {
36-
exec = newExec(description, now + 30 days, true, spellAction);
35+
exec = newExec(description, now + 30 days, spellAction);
3736
}
3837

3938
function newMonthlyExec(string memory description, address spellAction) public returns (address exec) {
40-
exec = newExec(description, now + 4 days, true, spellAction);
39+
exec = newExec(description, now + 4 days, spellAction);
4140
}
4241
}

src/test/DssAction.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ contract ActionTest is DSTest {
274274

275275
lib = new DssExecLib();
276276

277-
action = new DssTestAction(address(lib));
277+
action = new DssTestAction(address(lib), true);
278278

279279
init_collateral("gold", address(action));
280280

src/test/DssExec.t.sol

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ interface Hevm {
4141
contract DssLibSpellAction is DssAction { // This could be changed to a library if the lib is hardcoded and the constructor removed
4242

4343
// This can be hardcoded away later or can use the chain-log
44-
constructor(address lib) DssAction(lib) public {}
44+
constructor(address lib, bool ofcHrs) DssAction(lib, ofcHrs) public {}
4545

4646
uint256 constant MILLION = 10 ** 6;
4747

48-
function execute() external {
48+
function actions() public override {
4949
CollateralOpts memory XMPL_A = CollateralOpts({
5050
ilk: "XMPL-A",
5151
gem: 0xCE4F3774620764Ea881a8F8840Cbe0F701372283,
@@ -206,8 +206,7 @@ contract DssLibExecTest is DSTest, DSMath {
206206
spell = new DssExec(
207207
"A test dss exec spell", // Description
208208
now + 30 days, // Expiration
209-
true, // OfficeHours enabled
210-
address(new DssLibSpellAction(execlib))
209+
address(new DssLibSpellAction(execlib, true))
211210
);
212211

213212
//
@@ -581,8 +580,7 @@ contract DssLibExecTest is DSTest, DSMath {
581580
new DssExec(
582581
"Basic Spell", // Description
583582
now + 30 days, // Expiration
584-
true, // OfficeHours enabled
585-
address(new DssLibSpellAction(execlib))
583+
address(new DssLibSpellAction(execlib, true))
586584
);
587585
}
588586
}

src/test/DssExecFactory.t.sol

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ interface Hevm {
4242
contract DssLibSpellAction is DssAction { // This could be changed to a library if the lib is hardcoded and the constructor removed
4343

4444
// This can be hardcoded away later or can use the chain-log
45-
constructor(address lib) DssAction(lib) public {}
45+
constructor(address lib, bool ofcHrs) DssAction(lib, ofcHrs) public {}
4646

4747
uint256 constant MILLION = 10 ** 6;
4848

49-
function execute() external {
49+
function actions() public override {
5050
CollateralOpts memory XMPL_A = CollateralOpts({
5151
ilk: "XMPL-A",
5252
gem: 0xCE4F3774620764Ea881a8F8840Cbe0F701372283,
@@ -211,12 +211,11 @@ contract DssLibExecTest is DSTest, DSMath {
211211
factory = new DssExecFactory();
212212

213213
// Only an action needs to be crafted, it can be passed to the factory which is already deployed.
214-
action = new DssLibSpellAction(execlib);
214+
action = new DssLibSpellAction(execlib, true);
215215

216216
address _factorySpell = factory.newExec(
217217
"A test dss exec spell", // Description
218218
now + 30 days, // Expiration
219-
true, // OfficeHours enabled
220219
address(action)
221220
);
222221

@@ -599,7 +598,6 @@ contract DssLibExecTest is DSTest, DSMath {
599598
factory.newExec(
600599
"A test dss exec spell", // Description
601600
now + 30 days, // Expiration
602-
true, // OfficeHours enabled
603601
address(action)
604602
);
605603
}

src/test/DssTestAction.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import "../DssAction.sol";
2424

2525
contract DssTestAction is DssAction {
2626

27-
constructor(address lib) DssAction(lib) public {}
27+
constructor(address lib, bool ofcHrs) DssAction(lib, ofcHrs) public {}
28+
29+
function actions() public override {}
2830

2931
/**********************/
3032
/*** Authorizations ***/

0 commit comments

Comments
 (0)