diff --git a/contracts/delegation/DelegationController.sol b/contracts/delegation/DelegationController.sol
index 5464fbc33..d484ff17c 100644
--- a/contracts/delegation/DelegationController.sol
+++ b/contracts/delegation/DelegationController.sol
@@ -270,7 +270,7 @@ contract DelegationController is Permissions, ILocker {
SlashingSignal[] memory slashingSignals = processSlashesWithoutSignals(delegations[delegationId].holder);
- uint currentMonth = timeHelpers.timestampToMonth(now);
+ uint currentMonth = timeHelpers.getCurrentMonth();
delegations[delegationId].started = currentMonth.add(1);
_delegationExtras[delegationId].lastSlashingMonthBeforeDelegation = _slashesOfValidator[delegations[delegationId].validatorId].lastMonth;
@@ -402,7 +402,7 @@ contract DelegationController is Permissions, ILocker {
if (delegations[delegationId].started == 0) {
if (delegations[delegationId].finished == 0) {
TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers"));
- if (now < timeHelpers.getNextMonthStartFromDate(delegations[delegationId].created)) {
+ if (timeHelpers.getCurrentMonth() == timeHelpers.timestampToMonth(delegations[delegationId].created)) {
return State.PROPOSED;
} else {
return State.REJECTED;
@@ -412,13 +412,13 @@ contract DelegationController is Permissions, ILocker {
}
} else {
TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers"));
- if (now < timeHelpers.monthToTimestamp(delegations[delegationId].started)) {
+ if (timeHelpers.getCurrentMonth() < delegations[delegationId].started) {
return State.ACCEPTED;
} else {
if (delegations[delegationId].finished == 0) {
return State.DELEGATED;
} else {
- if (now < timeHelpers.monthToTimestamp(delegations[delegationId].finished)) {
+ if (timeHelpers.getCurrentMonth() < delegations[delegationId].finished) {
return State.UNDELEGATION_REQUESTED;
} else {
return State.COMPLETED;
@@ -579,7 +579,7 @@ contract DelegationController is Permissions, ILocker {
function getCurrentMonth() internal view returns (uint) {
TimeHelpers timeHelpers = TimeHelpers(contractManager.getContract("TimeHelpers"));
- return timeHelpers.timestampToMonth(now);
+ return timeHelpers.getCurrentMonth();
}
function _getAndUpdateLockedAmount(address wallet) internal returns (uint) {
diff --git a/contracts/delegation/TimeHelpers.sol b/contracts/delegation/TimeHelpers.sol
index 2c53bdb48..639b61c6d 100644
--- a/contracts/delegation/TimeHelpers.sol
+++ b/contracts/delegation/TimeHelpers.sol
@@ -29,70 +29,12 @@ contract TimeHelpers {
uint constant ZERO_YEAR = 2020;
- function getNextMonthStart() external view returns (uint timestamp) {
- return getNextMonthStartFromDate(now);
- }
-
- function calculateDelegationEndTime(
- uint requestTime,
- uint delegationPeriod,
- uint redelegationPeriod
- )
- external
- view
- returns (uint timestamp)
- {
- uint year;
- uint month;
- (year, month, ) = BokkyPooBahsDateTimeLibrary.timestampToDate(requestTime);
-
- month = month.add(delegationPeriod).add(1);
- if (month > 12) {
- year = year.add(month.sub(1).div(12));
- month = month.sub(1).mod(12).add(1);
- }
- timestamp = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, 1);
-
- if (now > timestamp) {
- uint currentYear;
- uint currentMonth;
- (currentYear, currentMonth, ) = BokkyPooBahsDateTimeLibrary.timestampToDate(now);
- currentMonth = currentMonth.add(currentYear.sub(year).mul(12));
-
- month = month.add(
- currentMonth.sub(month).div(redelegationPeriod).add(1).mul(redelegationPeriod));
- if (month > 12) {
- year = year.add(month.sub(1).div(12));
- month = month.sub(1).mod(12).add(1);
- }
- timestamp = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, 1);
- }
- }
-
function calculateProofOfUseLockEndTime(uint month, uint lockUpPeriodDays) external pure returns (uint timestamp) {
timestamp = BokkyPooBahsDateTimeLibrary.addDays(monthToTimestamp(month), lockUpPeriodDays);
}
function addMonths(uint fromTimestamp, uint n) external pure returns (uint) {
- uint year;
- uint month;
- uint day;
- uint hour;
- uint minute;
- uint second;
- (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(fromTimestamp);
- month = month.add(n);
- if (month > 12) {
- year = year.add(month.sub(1).div(12));
- month = month.sub(1).mod(12).add(1);
- }
- return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(
- year,
- month,
- day,
- hour,
- minute,
- second);
+ return BokkyPooBahsDateTimeLibrary.addMonths(fromTimestamp, n);
}
function getCurrentMonth() external view returns (uint) {
@@ -117,16 +59,4 @@ contract TimeHelpers {
require(month > 0, "Timestamp is too far in the past");
return month;
}
-
- function getNextMonthStartFromDate(uint dateTimestamp) public pure returns (uint timestamp) {
- uint year;
- uint month;
- (year, month, ) = BokkyPooBahsDateTimeLibrary.timestampToDate(dateTimestamp);
- month = month.add(1);
- if (month > 12) {
- year = year.add(1);
- month = 1;
- }
- timestamp = BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, 1);
- }
}
diff --git a/contracts/test/TimeHelpersWithDebug.sol b/contracts/test/TimeHelpersWithDebug.sol
new file mode 100644
index 000000000..fbba58953
--- /dev/null
+++ b/contracts/test/TimeHelpersWithDebug.sol
@@ -0,0 +1,44 @@
+/*
+ TimeHellpersWithDebug.sol - SKALE Manager
+ Copyright (C) 2019-Present SKALE Labs
+ @author Dmytro Stebaiev
+
+ SKALE Manager 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.
+
+ SKALE Manager 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 SKALE Manager. If not, see .
+*/
+
+pragma solidity 0.5.16;
+
+import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol";
+import "@openzeppelin/upgrades/contracts/Initializable.sol";
+
+import "../delegation/TimeHelpers.sol";
+
+
+contract TimeHelpersWithDebug is TimeHelpers, Ownable {
+ uint timeShift;
+
+ function getCurrentMonth() external view returns (uint) {
+ return timestampToMonth(now.add(timeShift));
+ }
+
+ function skipTime(uint sec) external onlyOwner {
+ timeShift = timeShift.add(sec);
+ }
+
+ function initialize() external initializer {
+ Ownable.initialize(msg.sender);
+ timeShift = 0;
+ }
+
+}
\ No newline at end of file
diff --git a/migrations/1_deploy_skale_manager_system.js b/migrations/1_deploy_skale_manager_system.js
index ff6d194a4..a522755a4 100644
--- a/migrations/1_deploy_skale_manager_system.js
+++ b/migrations/1_deploy_skale_manager_system.js
@@ -24,6 +24,7 @@ let erc1820Contract = erc1820Params.contractAddress;
let erc1820Sender = erc1820Params.senderAddress;
let erc1820Bytecode = erc1820Params.bytecode;
let erc1820Amount = "80000000000000000";
+const production = false; // TODO: change to true before launch
async function deploy(deployer, networkName, accounts) {
if (configFile.networks[networkName].host !== "" && configFile.networks[networkName].host !== undefined && configFile.networks[networkName].port !== "" && configFile.networks[networkName].port !== undefined) {
@@ -96,6 +97,9 @@ async function deploy(deployer, networkName, accounts) {
"SkaleManager",
"Pricing"
]
+ if (!production) {
+ contracts.push("TimeHelpersWithDebug");
+ }
contractsData = [];
for (const contract of contracts) {
@@ -119,6 +123,8 @@ async function deploy(deployer, networkName, accounts) {
console.log("contractManager address:", contract.address);
} else if (["TimeHelpers", "Decryption", "ECDH"].includes(contractName)) {
contract = await create(Object.assign({ contractAlias: contractName }, options));
+ } else if (["TimeHelpersWithDebug"].includes(contractName)) {
+ contract = await create(Object.assign({ contractAlias: contractName, methodName: 'initialize', methodArgs: [] }, options));
} else {
contract = await create(Object.assign({ contractAlias: contractName, methodName: 'initialize', methodArgs: [contractManager.address] }, options));
}
@@ -132,7 +138,12 @@ async function deploy(deployer, networkName, accounts) {
await contractManager.methods.setContractsAddress(contract, address).send({from: deployAccount}).then(function(res) {
console.log("Contract", contract, "with address", address, "is registered in Contract Manager");
});
- }
+ }
+ if (!production) {
+ await contractManager.methods.setContractsAddress("TimeHelpers", deployed.get("TimeHelpersWithDebug").address).send({from: deployAccount}).then(function(res) {
+ console.log("TimeHelpersWithDebug was enabled");
+ });
+ }
await deployer.deploy(SkaleToken, contractManager.address, [], {gas: gasLimit * gas_multiplier});
await contractManager.methods.setContractsAddress("SkaleToken", SkaleToken.address).send({from: deployAccount}).then(function(res) {
diff --git a/test/delegation/DelegationController.ts b/test/delegation/DelegationController.ts
index cde7aef1b..c6967f933 100644
--- a/test/delegation/DelegationController.ts
+++ b/test/delegation/DelegationController.ts
@@ -13,6 +13,7 @@ import { deployDelegationController } from "../utils/deploy/delegation/delegatio
import { deployTokenState } from "../utils/deploy/delegation/tokenState";
import { deployValidatorService } from "../utils/deploy/delegation/validatorService";
import { deploySkaleToken } from "../utils/deploy/skaleToken";
+import { deployTimeHelpersWithDebug } from "../utils/deploy/test/timeHelpersWithDebug";
import { Delegation, State } from "../utils/types";
chai.should();
chai.use(chaiAsPromised);
@@ -169,6 +170,24 @@ contract("DelegationController", ([owner, holder1, holder2, validator, validator
.should.be.rejectedWith("No permissions to accept request");
});
+ it("should allow for QA team to test delegation pipeline immediately", async () => {
+ const timeHelpersWithDebug = await deployTimeHelpersWithDebug(contractManager);
+ await contractManager.setContractsAddress("TimeHelpers", timeHelpersWithDebug.address);
+
+ await delegationController.acceptPendingDelegation(delegationId, {from: validator});
+ (await delegationController.getState(delegationId)).toNumber().should.be.equal(State.ACCEPTED);
+
+ await timeHelpersWithDebug.skipTime(month);
+ (await delegationController.getState(delegationId)).toNumber().should.be.equal(State.DELEGATED);
+
+ await delegationController.requestUndelegation(delegationId, {from: holder1});
+ (await delegationController.getState(delegationId)).toNumber()
+ .should.be.equal(State.UNDELEGATION_REQUESTED);
+
+ await timeHelpersWithDebug.skipTime(month * delegationPeriod);
+ (await delegationController.getState(delegationId)).toNumber().should.be.equal(State.COMPLETED);
+ });
+
describe("when delegation is accepted", async () => {
beforeEach(async () => {
await delegationController.acceptPendingDelegation(delegationId, {from: validator});
diff --git a/test/utils/deploy/test/timeHelpersWithDebug.ts b/test/utils/deploy/test/timeHelpersWithDebug.ts
new file mode 100644
index 000000000..8ace7559f
--- /dev/null
+++ b/test/utils/deploy/test/timeHelpersWithDebug.ts
@@ -0,0 +1,14 @@
+import { ContractManagerInstance, TimeHelpersWithDebugInstance } from "../../../../types/truffle-contracts";
+import { deployFunctionFactory } from "../factory";
+
+const deployTimeHelpersWithDebug: (contractManager: ContractManagerInstance) => Promise
+ = deployFunctionFactory("TimeHelpersWithDebug",
+ undefined,
+ async (contractManager: ContractManagerInstance) => {
+ const TimeHelpersWithDebug = artifacts.require("./TimeHelpersWithDebug");
+ const instance = await TimeHelpersWithDebug.new();
+ await instance.initialize();
+ return instance;
+ });
+
+export { deployTimeHelpersWithDebug };