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

Commit

Permalink
add timelock
Browse files Browse the repository at this point in the history
  • Loading branch information
jingleizhang committed Jan 28, 2021
1 parent ea7df30 commit 12d1ff8
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 163 deletions.
182 changes: 44 additions & 138 deletions contracts/Timelock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,173 +32,87 @@ pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";

contract Timelock {
using SafeMath for uint256;
using SafeMath for uint;

event NewAdmin(address indexed newAdmin);
event NewPendingAdmin(address indexed newPendingAdmin);
event NewDelay(uint256 indexed newDelay);
event CancelTransaction(
bytes32 indexed txHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 eta
);
event ExecuteTransaction(
bytes32 indexed txHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 eta
);
event QueueTransaction(
bytes32 indexed txHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 eta
);

uint256 public constant GRACE_PERIOD = 14 days;
uint256 public constant MINIMUM_DELAY = 2 days;
uint256 public constant MAXIMUM_DELAY = 30 days;
event NewDelay(uint indexed newDelay);
event CancelTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
event ExecuteTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
event QueueTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);

uint public constant GRACE_PERIOD = 14 days;
uint public constant MINIMUM_DELAY = 2 days;
uint public constant MAXIMUM_DELAY = 30 days;

address public admin;
address public pendingAdmin;
uint256 public delay;
uint public delay;

mapping (bytes32 => bool) public queuedTransactions;

mapping(bytes32 => bool) public queuedTransactions;

constructor(address admin_, uint256 delay_) public {
require(
delay_ >= MINIMUM_DELAY,
"Timelock::constructor: Delay must exceed minimum delay."
);
require(
delay_ <= MAXIMUM_DELAY,
"Timelock::setDelay: Delay must not exceed maximum delay."
);
constructor(address admin_, uint delay_) public {
require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay.");
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");

admin = admin_;
delay = delay_;
}

receive() external payable {}

function setDelay(uint256 delay_) public {
require(
msg.sender == address(this),
"Timelock::setDelay: Call must come from Timelock."
);
require(
delay_ >= MINIMUM_DELAY,
"Timelock::setDelay: Delay must exceed minimum delay."
);
require(
delay_ <= MAXIMUM_DELAY,
"Timelock::setDelay: Delay must not exceed maximum delay."
);
function() external payable { }

function setDelay(uint delay_) public {
require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock.");
require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay.");
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
delay = delay_;

emit NewDelay(delay);
}

function acceptAdmin() public {
require(
msg.sender == pendingAdmin,
"Timelock::acceptAdmin: Call must come from pendingAdmin."
);
require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin.");
admin = msg.sender;
pendingAdmin = address(0);

emit NewAdmin(admin);
}

function setPendingAdmin(address pendingAdmin_) public {
require(
msg.sender == address(this),
"Timelock::setPendingAdmin: Call must come from Timelock."
);
require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock.");
pendingAdmin = pendingAdmin_;

emit NewPendingAdmin(pendingAdmin);
}

function queueTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) public returns (bytes32) {
require(
msg.sender == admin,
"Timelock::queueTransaction: Call must come from admin."
);
require(
eta >= getBlockTimestamp().add(delay),
"Timelock::queueTransaction: Estimated execution block must satisfy delay."
);

bytes32 txHash = keccak256(
abi.encode(target, value, signature, data, eta)
);
function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public returns (bytes32) {
require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin.");
require(eta >= getBlockTimestamp().add(delay), "Timelock::queueTransaction: Estimated execution block must satisfy delay.");

bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
queuedTransactions[txHash] = true;

emit QueueTransaction(txHash, target, value, signature, data, eta);
return txHash;
}

function cancelTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) public {
require(
msg.sender == admin,
"Timelock::cancelTransaction: Call must come from admin."
);

bytes32 txHash = keccak256(
abi.encode(target, value, signature, data, eta)
);
function cancelTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public {
require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin.");

bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
queuedTransactions[txHash] = false;

emit CancelTransaction(txHash, target, value, signature, data, eta);
}

function executeTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) public payable returns (bytes memory) {
require(
msg.sender == admin,
"Timelock::executeTransaction: Call must come from admin."
);

bytes32 txHash = keccak256(
abi.encode(target, value, signature, data, eta)
);
require(
queuedTransactions[txHash],
"Timelock::executeTransaction: Transaction hasn't been queued."
);
require(
getBlockTimestamp() >= eta,
"Timelock::executeTransaction: Transaction hasn't surpassed time lock."
);
require(
getBlockTimestamp() <= eta.add(GRACE_PERIOD),
"Timelock::executeTransaction: Transaction is stale."
);
function executeTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public payable returns (bytes memory) {
require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin.");

bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued.");
require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock.");
require(getBlockTimestamp() <= eta.add(GRACE_PERIOD), "Timelock::executeTransaction: Transaction is stale.");

queuedTransactions[txHash] = false;

Expand All @@ -207,28 +121,20 @@ contract Timelock {
if (bytes(signature).length == 0) {
callData = data;
} else {
callData = abi.encodePacked(
bytes4(keccak256(bytes(signature))),
data
);
callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
}

// solium-disable-next-line security/no-call-value
(bool success, bytes memory returnData) = target.call{value: value}(
callData
);
require(
success,
"Timelock::executeTransaction: Transaction execution reverted."
);
(bool success, bytes memory returnData) = target.call.value(value)(callData);
require(success, "Timelock::executeTransaction: Transaction execution reverted.");

emit ExecuteTransaction(txHash, target, value, signature, data, eta);

return returnData;
}

function getBlockTimestamp() internal view returns (uint256) {
function getBlockTimestamp() internal view returns (uint) {
// solium-disable-next-line security/no-block-members
return block.timestamp;
}
}
}
27 changes: 4 additions & 23 deletions contracts/XDEX.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,26 @@ import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
contract XDEX is ERC20, ERC20Detailed {
address public core;

mapping(address => bool) public minters;

event CoreTransferred(address indexed _core, address indexed _coreNew);
event AddMinter(address indexed _minter);
event RemoveMinter(address indexed _minter);
event SET_CORE(address indexed core, address indexed _core);

constructor() public ERC20Detailed("XDEFI Governance Token", "XDEX", 18) {
core = msg.sender;
}

modifier onlyCore() {
require(msg.sender == core, "Not Authorized, Only Core");
_;
}

modifier onlyMinter() {
require(minters[msg.sender], "Not Authorized, Only Minter");
require(msg.sender == core, "Not Authorized");
_;
}

function setCore(address _core) public onlyCore {
emit CoreTransferred(core, _core);
emit SET_CORE(core, _core);
core = _core;
}

function mint(address account, uint256 amount) public onlyMinter {
function mint(address account, uint256 amount) public onlyCore {
_mint(account, amount);
}

function addMinter(address _minter) public onlyCore {
minters[_minter] = true;
emit AddMinter(_minter);
}

function removeMinter(address _minter) public onlyCore {
minters[_minter] = false;
emit RemoveMinter(_minter);
}

function burnForSelf(uint256 amount) external {
_burn(msg.sender, amount);
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
},
"homepage": "https://github.com/xdefilab/xdefi-governance-token#readme",
"dependencies": {
"@openzeppelin/contracts": "^2.5.1",
"@openzeppelin/contracts": "2.5.1",
"@openzeppelin/test-helpers": "^0.5.6",
"@truffle/hdwallet-provider": "^1.0.41",
"decimal.js": "10.2.0",
Expand Down
24 changes: 24 additions & 0 deletions scripts/calculateContractBytecode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// This simple script tells you how big your contract byte code is and how much you have until you exceed
// the current block limit as defined by EIP170.

const argv = require("minimist")(process.argv.slice(), { string: ["contract"] });
const contractName = argv.contract;

if (!contractName) {
console.log("Please enter the contract name as a parameter as `--contract <name>`.");
return;
}
var child = require("child_process").exec("truffle compile");
child.stdout.pipe(process.stdout);
child.on("exit", function() {
console.log("finished compiling 🚀!");
console.log("loading", contractName + ".json");
let obj = require("./../build/contracts/" + contractName + ".json");

const byteCodeSize = (obj.bytecode.length - 2) / 2;
const remainingSize = 2 ** 14 + 2 ** 13 - (obj.bytecode.length - 2) / 2;
console.log("Contract is", byteCodeSize, "bytes in size.");
console.log("This leaves a total of", remainingSize, "bytes within the EIP170 limit 🔥.");

process.exit();
});
17 changes: 17 additions & 0 deletions scripts/start_ganache.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh

source /etc/bashrc

BIN=ganache-cli

res=`ps aux | grep ${BIN} | grep -v grep | awk '{print $2}'`
if [ "$res" == "" ]; then
echo "the ${BIN} is not running, begin startup..."
else
echo 'current running pid is '$res', begin to stopping...'

kill -9 `ps aux | grep ${BIN} |egrep -v "grep"|awk '{print $2}'` && sleep 1s && echo -e "${BIN} killed successfully"
fi

ganache-cli --chainId="0x2a" --networkId="0x2a" --port="8545" --mnemonic "copy obey episode awake damp vacant protect hold wish primary travel shy" --gasLimit=3000000000000 --gasPrice=20000

Loading

0 comments on commit 12d1ff8

Please sign in to comment.