Skip to content
This repository was archived by the owner on Oct 8, 2024. It is now read-only.

Commit 79cd6ac

Browse files
Refactor nextCastTime to DssExecLib (#74)
1 parent a0a6e30 commit 79cd6ac

12 files changed

+128
-53
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ Below is an outline of all functions used in the library.
9494
- `setChangelogIPFS(string memory _ipfsHash)`: Set IPFS hash of IPFS changelog in MCD on-chain changelog.
9595
- `setChangelogSHA256(string memory _SHA256Sum)`: Set SHA256 hash in MCD on-chain changelog.
9696

97+
### Time Management
98+
- `canCast(uint40 _ts, bool _officeHours) returns (bool)`: Use to determine whether a timestamp is within the office hours window.
99+
- `nextCastTime(uint40 _eta, uint40 _ts, bool _officeHours) returns (uint256)`: Use to return the timestamp of the first available time after eta that a spell can be cast.
100+
97101
### Authorizations
98102
- `authorize(address _base, address _ward)`: Give an address authorization to perform auth actions on the contract.
99103
- `deauthorize(address _base, address _ward)`: Revoke contract authorization from an address.

build.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set -e
44
# shellcheck disable=SC1091
55
source "./allow-optimize.sh"
66

7-
DAPP_BUILD_OPTIMIZE=1 DAPP_BUILD_OPTIMIZE_RUNS=200 dapp --use solc:0.6.11 build
7+
DAPP_BUILD_OPTIMIZE=1 DAPP_BUILD_OPTIMIZE_RUNS=200 dapp --use solc:0.6.12 build

shell.nix

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
}: with dappPkgs;
66

77
mkShell {
8-
DAPP_SOLC = solc-static-versions.solc_0_6_11 + "/bin/solc-0.6.11";
8+
DAPP_SOLC = solc-static-versions.solc_0_6_12 + "/bin/solc-0.6.12";
99
DAPP_BUILD_OPTIMIZE = 1;
1010
DAPP_BUILD_OPTIMIZE_RUNS = 200;
1111
buildInputs = [

src/CollateralOpts.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pragma solidity ^0.6.11;
1+
pragma solidity ^0.6.12;
22

33
struct CollateralOpts {
44
bytes32 ilk;

src/DssAction.sol

+11-10
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// You should have received a copy of the GNU Affero General Public License
1818
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1919

20-
pragma solidity ^0.6.11;
20+
pragma solidity ^0.6.12;
2121

2222
import { DssExecLib } from "./DssExecLib.sol";
2323
import { CollateralOpts } from "./CollateralOpts.sol";
@@ -30,6 +30,12 @@ abstract contract DssAction {
3030

3131
using DssExecLib for *;
3232

33+
// Modifier used to limit execution time when office hours is enabled
34+
modifier limited {
35+
require(DssExecLib.canCast(uint40(block.timestamp), officeHours()), "Outside office hours");
36+
_;
37+
}
38+
3339
// Office Hours defaults to true by default.
3440
// To disable office hours, override this function and
3541
// return false in the inherited action.
@@ -47,14 +53,9 @@ abstract contract DssAction {
4753
// By keeping this function public we allow simulations of `execute()` on the actions outside of the cast time.
4854
function actions() public virtual;
4955

50-
// Modifier required to
51-
modifier limited {
52-
if (officeHours()) {
53-
uint day = (block.timestamp / 1 days + 3) % 7;
54-
require(day < 5, "Can only be cast on a weekday");
55-
uint hour = block.timestamp / 1 hours % 24;
56-
require(hour >= 14 && hour < 21, "Outside office hours");
57-
}
58-
_;
56+
// Returns the next available cast time
57+
function nextCastTime(uint256 eta) external returns (uint256 castTime) {
58+
require(eta <= uint40(-1));
59+
castTime = DssExecLib.nextCastTime(uint40(eta), uint40(block.timestamp), officeHours());
5960
}
6061
}

src/DssExec.sol

+3-25
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// You should have received a copy of the GNU Affero General Public License
1818
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1919

20-
pragma solidity ^0.6.11;
20+
pragma solidity ^0.6.12;
2121

2222
interface PauseAbstract {
2323
function delay() external view returns (uint256);
@@ -31,6 +31,7 @@ interface Changelog {
3131

3232
interface SpellAction {
3333
function officeHours() external view returns (bool);
34+
function nextCastTime(uint256) external view returns (uint256);
3435
}
3536

3637
contract DssExec {
@@ -54,30 +55,7 @@ contract DssExec {
5455
}
5556

5657
function nextCastTime() external view returns (uint256 castTime) {
57-
require(eta != 0, "DssExec/spell-not-scheduled");
58-
castTime = block.timestamp > eta ? block.timestamp : eta; // Any day at XX:YY
59-
60-
if (SpellAction(action).officeHours()) {
61-
uint256 day = (castTime / 1 days + 3) % 7;
62-
uint256 hour = castTime / 1 hours % 24;
63-
uint256 minute = castTime / 1 minutes % 60;
64-
uint256 second = castTime % 60;
65-
66-
if (day >= 5) {
67-
castTime += (6 - day) * 1 days; // Go to Sunday XX:YY
68-
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC Monday
69-
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
70-
} else {
71-
if (hour >= 21) {
72-
if (day == 4) castTime += 2 days; // If Friday, fast forward to Sunday XX:YY
73-
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC next day
74-
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
75-
} else if (hour < 14) {
76-
castTime += (14 - hour) * 1 hours; // Go to 14:YY UTC same day
77-
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
78-
}
79-
}
80-
}
58+
return SpellAction(action).nextCastTime(eta);
8159
}
8260

8361
// @param _description A string description of the spell

src/DssExecLib.sol

+63-10
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@
1616
//
1717
// You should have received a copy of the GNU Affero General Public License
1818
// along with this program. If not, see <https://www.gnu.org/licenses/>.
19-
pragma solidity ^0.6.11;
19+
pragma solidity ^0.6.12;
2020
pragma experimental ABIEncoderV2;
2121

2222
import { CollateralOpts } from "./CollateralOpts.sol";
2323

24-
2524
interface Initializable {
2625
function init(bytes32) external;
2726
}
@@ -147,29 +146,28 @@ library DssExecLib {
147146
uint256 constant internal BPS_ONE_HUNDRED_PCT = 100 * BPS_ONE_PCT;
148147
uint256 constant internal RATES_ONE_HUNDRED_PCT = 1000000021979553151239153027;
149148

150-
151149
/**********************/
152150
/*** Math Functions ***/
153151
/**********************/
154-
function add(uint x, uint y) internal pure returns (uint z) {
152+
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
155153
require((z = x + y) >= x);
156154
}
157-
function sub(uint x, uint y) internal pure returns (uint z) {
155+
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
158156
require((z = x - y) <= x);
159157
}
160-
function mul(uint x, uint y) internal pure returns (uint z) {
158+
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
161159
require(y == 0 || (z = x * y) / y == x);
162160
}
163-
function wmul(uint x, uint y) internal pure returns (uint z) {
161+
function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
164162
z = add(mul(x, y), WAD / 2) / WAD;
165163
}
166-
function rmul(uint x, uint y) internal pure returns (uint z) {
164+
function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
167165
z = add(mul(x, y), RAY / 2) / RAY;
168166
}
169-
function wdiv(uint x, uint y) internal pure returns (uint z) {
167+
function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
170168
z = add(mul(x, WAD), y / 2) / y;
171169
}
172-
function rdiv(uint x, uint y) internal pure returns (uint z) {
170+
function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
173171
z = add(mul(x, RAY), y / 2) / y;
174172
}
175173

@@ -272,6 +270,61 @@ library DssExecLib {
272270
DssVat(vat()).nope(_usr);
273271
}
274272

273+
/******************************/
274+
/*** OfficeHours Management ***/
275+
/******************************/
276+
277+
/**
278+
@dev Returns true if a time is within office hours range
279+
@param _ts The timestamp to check, usually block.timestamp
280+
@param _officeHours true if office hours is enabled.
281+
@return true if time is in castable range
282+
*/
283+
function canCast(uint40 _ts, bool _officeHours) public pure returns (bool) {
284+
if (_officeHours) {
285+
uint256 day = (_ts / 1 days + 3) % 7;
286+
if (day >= 5) { return false; } // Can only be cast on a weekday
287+
uint256 hour = _ts / 1 hours % 24;
288+
if (hour < 14 || hour >= 21) { return false; } // Outside office hours
289+
}
290+
return true;
291+
}
292+
293+
/**
294+
@dev Calculate the next available cast time in epoch seconds
295+
@param _eta The scheduled time of the spell plus the pause delay
296+
@param _ts The current timestamp, usually block.timestamp
297+
@param _officeHours true if office hours is enabled.
298+
@return castTime The next available cast timestamp
299+
*/
300+
function nextCastTime(uint40 _eta, uint40 _ts, bool _officeHours) public pure returns (uint256 castTime) {
301+
require(_eta != 0); // "DssExecLib/invalid eta"
302+
require(_ts != 0); // "DssExecLib/invalid ts"
303+
castTime = _ts > _eta ? _ts : _eta; // Any day at XX:YY
304+
305+
if (_officeHours) {
306+
uint256 day = (castTime / 1 days + 3) % 7;
307+
uint256 hour = castTime / 1 hours % 24;
308+
uint256 minute = castTime / 1 minutes % 60;
309+
uint256 second = castTime % 60;
310+
311+
if (day >= 5) {
312+
castTime += (6 - day) * 1 days; // Go to Sunday XX:YY
313+
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC Monday
314+
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
315+
} else {
316+
if (hour >= 21) {
317+
if (day == 4) castTime += 2 days; // If Friday, fast forward to Sunday XX:YY
318+
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC next day
319+
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
320+
} else if (hour < 14) {
321+
castTime += (14 - hour) * 1 hours; // Go to 14:YY UTC same day
322+
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
323+
}
324+
}
325+
}
326+
}
327+
275328
/**************************/
276329
/*** Accumulating Rates ***/
277330
/**************************/

src/test/DssAction.t.sol

+32-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// You should have received a copy of the GNU Affero General Public License
1818
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1919

20-
pragma solidity ^0.6.11;
20+
pragma solidity ^0.6.12;
2121
pragma experimental ABIEncoderV2;
2222

2323
import "ds-test/test.sol";
@@ -304,6 +304,37 @@ contract ActionTest is DSTest {
304304
govGuard.setRoot(address(action));
305305
}
306306

307+
// /******************************/
308+
// /*** OfficeHours Management ***/
309+
// /******************************/
310+
311+
function test_canCast() public {
312+
assertTrue(action.canCast_test(1616169600, true)); // Friday 2021/03/19, 4:00:00 PM GMT
313+
314+
assertTrue(action.canCast_test(1616169600, false)); // Friday 2021/03/19, 4:00:00 PM GMT
315+
assertTrue(action.canCast_test(1616256000, false)); // Saturday 2021/03/20, 4:00:00 PM GMT
316+
}
317+
318+
function testFail_canCast() public {
319+
assertTrue(action.canCast_test(1616256000, true)); // Saturday 2021/03/20, 4:00:00 PM GMT
320+
}
321+
322+
function test_nextCastTime() public {
323+
assertEq(action.nextCastTime_test(1616169600, 1616169600, true), 1616169600);
324+
assertEq(action.nextCastTime_test(1616169600, 1616169600, false), 1616169600);
325+
326+
assertEq(action.nextCastTime_test(1616256000, 1616256000, true), 1616421600);
327+
assertEq(action.nextCastTime_test(1616256000, 1616256000, false), 1616256000);
328+
}
329+
330+
function testFail_nextCastTime_eta_zero() public {
331+
action.nextCastTime_test(0, 1616256000, false);
332+
}
333+
334+
function testFail_nextCastTime_ts_zero() public {
335+
action.nextCastTime_test(1616256000, 0, false);
336+
}
337+
307338
// /**********************/
308339
// /*** Authorizations ***/
309340
// /**********************/

src/test/DssExec.t.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// You should have received a copy of the GNU Affero General Public License
1818
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1919

20-
pragma solidity ^0.6.11;
20+
pragma solidity ^0.6.12;
2121
pragma experimental ABIEncoderV2;
2222

2323
import "ds-test/test.sol";

src/test/DssTestAction.sol

+9-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// You should have received a copy of the GNU Affero General Public License
1818
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1919

20-
pragma solidity ^0.6.11;
20+
pragma solidity ^0.6.12;
2121
pragma experimental ABIEncoderV2;
2222

2323
import "../DssAction.sol";
@@ -36,6 +36,14 @@ contract DssTestAction is DssAction {
3636

3737
function actions() public override {}
3838

39+
function canCast_test(uint40 ts, bool officeHours) public pure returns (bool) {
40+
return DssExecLib.canCast(ts, officeHours);
41+
}
42+
43+
function nextCastTime_test(uint40 eta, uint40 ts, bool officeHours) public pure returns (uint256) {
44+
return DssExecLib.nextCastTime(eta, ts, officeHours);
45+
}
46+
3947
/**********************/
4048
/*** Authorizations ***/
4149
/**********************/

src/test/rates.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pragma solidity ^0.6.11;
1+
pragma solidity ^0.6.12;
22

33
contract Rates {
44

test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ set -e
66
# shellcheck disable=SC1091
77
source "./allow-optimize.sh"
88

9-
DAPP_BUILD_OPTIMIZE=1 DAPP_BUILD_OPTIMIZE_RUNS=200 dapp --use solc:0.6.11 test -v --rpc-url="$ETH_RPC_URL"
9+
DAPP_BUILD_OPTIMIZE=1 DAPP_BUILD_OPTIMIZE_RUNS=200 dapp --use solc:0.6.12 test -v --rpc-url="$ETH_RPC_URL"

0 commit comments

Comments
 (0)