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

Commit

Permalink
Refactor nextCastTime to DssExecLib (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
brianmcmichael authored Apr 12, 2021
1 parent a0a6e30 commit 79cd6ac
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 53 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ Below is an outline of all functions used in the library.
- `setChangelogIPFS(string memory _ipfsHash)`: Set IPFS hash of IPFS changelog in MCD on-chain changelog.
- `setChangelogSHA256(string memory _SHA256Sum)`: Set SHA256 hash in MCD on-chain changelog.

### Time Management
- `canCast(uint40 _ts, bool _officeHours) returns (bool)`: Use to determine whether a timestamp is within the office hours window.
- `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.

### Authorizations
- `authorize(address _base, address _ward)`: Give an address authorization to perform auth actions on the contract.
- `deauthorize(address _base, address _ward)`: Revoke contract authorization from an address.
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ set -e
# shellcheck disable=SC1091
source "./allow-optimize.sh"

DAPP_BUILD_OPTIMIZE=1 DAPP_BUILD_OPTIMIZE_RUNS=200 dapp --use solc:0.6.11 build
DAPP_BUILD_OPTIMIZE=1 DAPP_BUILD_OPTIMIZE_RUNS=200 dapp --use solc:0.6.12 build
2 changes: 1 addition & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
}: with dappPkgs;

mkShell {
DAPP_SOLC = solc-static-versions.solc_0_6_11 + "/bin/solc-0.6.11";
DAPP_SOLC = solc-static-versions.solc_0_6_12 + "/bin/solc-0.6.12";
DAPP_BUILD_OPTIMIZE = 1;
DAPP_BUILD_OPTIMIZE_RUNS = 200;
buildInputs = [
Expand Down
2 changes: 1 addition & 1 deletion src/CollateralOpts.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.6.11;
pragma solidity ^0.6.12;

struct CollateralOpts {
bytes32 ilk;
Expand Down
21 changes: 11 additions & 10 deletions src/DssAction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// 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.6.11;
pragma solidity ^0.6.12;

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

using DssExecLib for *;

// Modifier used to limit execution time when office hours is enabled
modifier limited {
require(DssExecLib.canCast(uint40(block.timestamp), officeHours()), "Outside office hours");
_;
}

// Office Hours defaults to true by default.
// To disable office hours, override this function and
// return false in the inherited action.
Expand All @@ -47,14 +53,9 @@ abstract contract DssAction {
// By keeping this function public we allow simulations of `execute()` on the actions outside of the cast time.
function actions() public virtual;

// Modifier required to
modifier limited {
if (officeHours()) {
uint day = (block.timestamp / 1 days + 3) % 7;
require(day < 5, "Can only be cast on a weekday");
uint hour = block.timestamp / 1 hours % 24;
require(hour >= 14 && hour < 21, "Outside office hours");
}
_;
// Returns the next available cast time
function nextCastTime(uint256 eta) external returns (uint256 castTime) {
require(eta <= uint40(-1));
castTime = DssExecLib.nextCastTime(uint40(eta), uint40(block.timestamp), officeHours());
}
}
28 changes: 3 additions & 25 deletions src/DssExec.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// 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.6.11;
pragma solidity ^0.6.12;

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

interface SpellAction {
function officeHours() external view returns (bool);
function nextCastTime(uint256) external view returns (uint256);
}

contract DssExec {
Expand All @@ -54,30 +55,7 @@ contract DssExec {
}

function nextCastTime() external view returns (uint256 castTime) {
require(eta != 0, "DssExec/spell-not-scheduled");
castTime = block.timestamp > eta ? block.timestamp : eta; // Any day at XX:YY

if (SpellAction(action).officeHours()) {
uint256 day = (castTime / 1 days + 3) % 7;
uint256 hour = castTime / 1 hours % 24;
uint256 minute = castTime / 1 minutes % 60;
uint256 second = castTime % 60;

if (day >= 5) {
castTime += (6 - day) * 1 days; // Go to Sunday XX:YY
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC Monday
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
} else {
if (hour >= 21) {
if (day == 4) castTime += 2 days; // If Friday, fast forward to Sunday XX:YY
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC next day
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
} else if (hour < 14) {
castTime += (14 - hour) * 1 hours; // Go to 14:YY UTC same day
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
}
}
}
return SpellAction(action).nextCastTime(eta);
}

// @param _description A string description of the spell
Expand Down
73 changes: 63 additions & 10 deletions src/DssExecLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
//
// 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.6.11;
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

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


interface Initializable {
function init(bytes32) external;
}
Expand Down Expand Up @@ -147,29 +146,28 @@ library DssExecLib {
uint256 constant internal BPS_ONE_HUNDRED_PCT = 100 * BPS_ONE_PCT;
uint256 constant internal RATES_ONE_HUNDRED_PCT = 1000000021979553151239153027;


/**********************/
/*** Math Functions ***/
/**********************/
function add(uint x, uint y) internal pure returns (uint z) {
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x);
}
function mul(uint x, uint y) internal pure returns (uint z) {
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x);
}
function wmul(uint x, uint y) internal pure returns (uint z) {
function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, RAY), y / 2) / y;
}

Expand Down Expand Up @@ -272,6 +270,61 @@ library DssExecLib {
DssVat(vat()).nope(_usr);
}

/******************************/
/*** OfficeHours Management ***/
/******************************/

/**
@dev Returns true if a time is within office hours range
@param _ts The timestamp to check, usually block.timestamp
@param _officeHours true if office hours is enabled.
@return true if time is in castable range
*/
function canCast(uint40 _ts, bool _officeHours) public pure returns (bool) {
if (_officeHours) {
uint256 day = (_ts / 1 days + 3) % 7;
if (day >= 5) { return false; } // Can only be cast on a weekday
uint256 hour = _ts / 1 hours % 24;
if (hour < 14 || hour >= 21) { return false; } // Outside office hours
}
return true;
}

/**
@dev Calculate the next available cast time in epoch seconds
@param _eta The scheduled time of the spell plus the pause delay
@param _ts The current timestamp, usually block.timestamp
@param _officeHours true if office hours is enabled.
@return castTime The next available cast timestamp
*/
function nextCastTime(uint40 _eta, uint40 _ts, bool _officeHours) public pure returns (uint256 castTime) {
require(_eta != 0); // "DssExecLib/invalid eta"
require(_ts != 0); // "DssExecLib/invalid ts"
castTime = _ts > _eta ? _ts : _eta; // Any day at XX:YY

if (_officeHours) {
uint256 day = (castTime / 1 days + 3) % 7;
uint256 hour = castTime / 1 hours % 24;
uint256 minute = castTime / 1 minutes % 60;
uint256 second = castTime % 60;

if (day >= 5) {
castTime += (6 - day) * 1 days; // Go to Sunday XX:YY
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC Monday
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
} else {
if (hour >= 21) {
if (day == 4) castTime += 2 days; // If Friday, fast forward to Sunday XX:YY
castTime += (24 - hour + 14) * 1 hours; // Go to 14:YY UTC next day
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
} else if (hour < 14) {
castTime += (14 - hour) * 1 hours; // Go to 14:YY UTC same day
castTime -= minute * 1 minutes + second; // Go to 14:00 UTC
}
}
}
}

/**************************/
/*** Accumulating Rates ***/
/**************************/
Expand Down
33 changes: 32 additions & 1 deletion src/test/DssAction.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// 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.6.11;
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "ds-test/test.sol";
Expand Down Expand Up @@ -304,6 +304,37 @@ contract ActionTest is DSTest {
govGuard.setRoot(address(action));
}

// /******************************/
// /*** OfficeHours Management ***/
// /******************************/

function test_canCast() public {
assertTrue(action.canCast_test(1616169600, true)); // Friday 2021/03/19, 4:00:00 PM GMT

assertTrue(action.canCast_test(1616169600, false)); // Friday 2021/03/19, 4:00:00 PM GMT
assertTrue(action.canCast_test(1616256000, false)); // Saturday 2021/03/20, 4:00:00 PM GMT
}

function testFail_canCast() public {
assertTrue(action.canCast_test(1616256000, true)); // Saturday 2021/03/20, 4:00:00 PM GMT
}

function test_nextCastTime() public {
assertEq(action.nextCastTime_test(1616169600, 1616169600, true), 1616169600);
assertEq(action.nextCastTime_test(1616169600, 1616169600, false), 1616169600);

assertEq(action.nextCastTime_test(1616256000, 1616256000, true), 1616421600);
assertEq(action.nextCastTime_test(1616256000, 1616256000, false), 1616256000);
}

function testFail_nextCastTime_eta_zero() public {
action.nextCastTime_test(0, 1616256000, false);
}

function testFail_nextCastTime_ts_zero() public {
action.nextCastTime_test(1616256000, 0, false);
}

// /**********************/
// /*** Authorizations ***/
// /**********************/
Expand Down
2 changes: 1 addition & 1 deletion src/test/DssExec.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// 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.6.11;
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "ds-test/test.sol";
Expand Down
10 changes: 9 additions & 1 deletion src/test/DssTestAction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// 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.6.11;
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

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

function actions() public override {}

function canCast_test(uint40 ts, bool officeHours) public pure returns (bool) {
return DssExecLib.canCast(ts, officeHours);
}

function nextCastTime_test(uint40 eta, uint40 ts, bool officeHours) public pure returns (uint256) {
return DssExecLib.nextCastTime(eta, ts, officeHours);
}

/**********************/
/*** Authorizations ***/
/**********************/
Expand Down
2 changes: 1 addition & 1 deletion src/test/rates.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity ^0.6.11;
pragma solidity ^0.6.12;

contract Rates {

Expand Down
2 changes: 1 addition & 1 deletion test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ set -e
# shellcheck disable=SC1091
source "./allow-optimize.sh"

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

0 comments on commit 79cd6ac

Please sign in to comment.