mirror of
https://github.com/Instadapp/dsa-governance.git
synced 2024-07-29 22:27:52 +00:00
Added upgradable token and pause logics
This commit is contained in:
parent
3c494ce007
commit
3135dbe7b1
|
@ -1,54 +1,24 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import {
|
||||
TokenDelegateStorageV1,
|
||||
TokenEvents,
|
||||
TimelockInterface,
|
||||
TokenInterface
|
||||
} from "./TokenInterfaces.sol";
|
||||
import { SafeMath } from "./SafeMath.sol";
|
||||
|
||||
// TODO - Rename it
|
||||
contract Token {
|
||||
/// @notice EIP-20 token name for this token
|
||||
string public constant name = "<Token Name>"; // TODO - Replace it
|
||||
|
||||
/// @notice EIP-20 token symbol for this token
|
||||
string public constant symbol = "<TKN>"; // TODO - Replace it
|
||||
|
||||
// TODO @thrilok209 @KaymasJain - Rename it
|
||||
contract TokenDelegate is TokenDelegateStorageV1, TokenEvents {
|
||||
/// @notice EIP-20 token decimals for this token
|
||||
uint8 public constant decimals = 18;
|
||||
|
||||
/// @notice Total number of tokens in circulation
|
||||
uint public totalSupply = 10000000e18; // TODO - Replace it
|
||||
|
||||
/// @notice Token minter
|
||||
address public minter;
|
||||
|
||||
/// @notice The timestamp after which minting may occur
|
||||
uint public mintingAllowedAfter;
|
||||
|
||||
/// @notice Minimum time between mints
|
||||
uint32 public constant minimumTimeBetweenMints = 1 days * 7; // TODO - Replace it
|
||||
uint32 public constant minimumTimeBetweenMints = 1 days * 7; // TODO @thrilok209 @KaymasJain - Replace it
|
||||
|
||||
/// @notice Cap on the percentage of totalSupply that can be minted at each mint
|
||||
uint8 public constant mintCap = 2; // TODO - Replace it
|
||||
|
||||
// Allowance amounts on behalf of others
|
||||
mapping (address => mapping (address => uint96)) internal allowances;
|
||||
|
||||
// Official record of token balances for each account
|
||||
mapping (address => uint96) internal balances;
|
||||
|
||||
/// @notice A record of each accounts delegate
|
||||
mapping (address => address) public delegates;
|
||||
|
||||
/// @notice A checkpoint for marking number of votes from a given block
|
||||
struct Checkpoint {
|
||||
uint32 fromBlock;
|
||||
uint96 votes;
|
||||
}
|
||||
|
||||
/// @notice A record of votes checkpoints for each account, by index
|
||||
mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
|
||||
|
||||
/// @notice The number of checkpoints for each account
|
||||
mapping (address => uint32) public numCheckpoints;
|
||||
uint8 public constant mintCap = 2; // TODO @thrilok209 @KaymasJain - Replace it
|
||||
|
||||
/// @notice The EIP-712 typehash for the contract's domain
|
||||
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
|
||||
|
@ -59,32 +29,27 @@ contract Token {
|
|||
/// @notice The EIP-712 typehash for the permit struct used by the contract
|
||||
bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
|
||||
|
||||
/// @notice A record of states for signing / validating signatures
|
||||
mapping (address => uint) public nonces;
|
||||
|
||||
/// @notice An event thats emitted when an account changes its delegate
|
||||
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
|
||||
|
||||
/// @notice An event thats emitted when a delegate account's vote balance changes
|
||||
event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
|
||||
|
||||
/// @notice An event thats emitted when the minter changes
|
||||
event MinterChanged(address indexed oldMinter, address indexed newMinter);
|
||||
|
||||
/// @notice The standard EIP-20 transfer event
|
||||
event Transfer(address indexed from, address indexed to, uint256 amount);
|
||||
|
||||
/// @notice The standard EIP-20 approval event
|
||||
event Approval(address indexed owner, address indexed spender, uint256 amount);
|
||||
|
||||
constructor(address account, address minter_, uint mintingAllowedAfter_) {
|
||||
require(mintingAllowedAfter_ >= block.timestamp, "Tkn::constructor: minting can only begin after deployment");
|
||||
// TODO @mubaris - add comment of each parameter.
|
||||
function initialize(address account, address minter_, uint mintingAllowedAfter_, bool transferPaused_) public {
|
||||
require(mintingAllowedAfter == 0, "Token::initialize: can only initialize once");
|
||||
require(address(minter) == address(0), "Token::initialize: can only initialize once");
|
||||
require(mintingAllowedAfter_ >= block.timestamp, "Token::constructor: minting can only begin after deployment");
|
||||
require(msg.sender == minter, "Token::initialize: admin only");
|
||||
// TODO @mubaris - anything else to add in require statements?
|
||||
|
||||
balances[account] = uint96(totalSupply);
|
||||
emit Transfer(address(0), account, totalSupply);
|
||||
minter = minter_;
|
||||
emit MinterChanged(address(0), minter);
|
||||
mintingAllowedAfter = mintingAllowedAfter_;
|
||||
transferPaused = transferPaused_;
|
||||
|
||||
if (transferPaused) {
|
||||
emit TransferPaused(msg.sender);
|
||||
} else {
|
||||
emit TransferUnpaused(msg.sender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,6 +62,24 @@ contract Token {
|
|||
minter = minter_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Pause the token transfer
|
||||
*/
|
||||
function pauseTransfer() external {
|
||||
require(msg.sender == minter, "Tkn::pauseTransfer: only the minter can pause token transfer");
|
||||
transferPaused = true;
|
||||
emit TransferPaused(msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Unpause the token transfer
|
||||
*/
|
||||
function unpauseTransfer() external {
|
||||
require(msg.sender == minter, "Tkn::unpauseTransfer: only the minter can unpause token transfer");
|
||||
transferPaused = false;
|
||||
emit TransferUnpaused(msg.sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
|
||||
* @param account The address of the account holding the funds
|
||||
|
@ -321,6 +304,7 @@ contract Token {
|
|||
}
|
||||
|
||||
function _transferTokens(address src, address dst, uint96 amount) internal {
|
||||
require(!transferPaused, "Tkn::_transferTokens: transfer paused");
|
||||
require(src != address(0), "Tkn::_transferTokens: cannot transfer from the zero address");
|
||||
require(dst != address(0), "Tkn::_transferTokens: cannot transfer to the zero address");
|
||||
|
82
contracts/TokenDelegator.sol
Normal file
82
contracts/TokenDelegator.sol
Normal file
|
@ -0,0 +1,82 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import { TokenDelegatorStorage, TokenEvents } from "./TokenInterfaces.sol";
|
||||
|
||||
contract TokenDelegator is TokenDelegatorStorage, TokenEvents {
|
||||
constructor(
|
||||
address account,
|
||||
address minter_,
|
||||
address implementation_,
|
||||
uint mintingAllowedAfter_,
|
||||
uint changeImplementationAfter_
|
||||
) {
|
||||
// Admin set to msg.sender for initialization
|
||||
minter = msg.sender;
|
||||
|
||||
delegateTo(
|
||||
implementation_,
|
||||
abi.encodeWithSignature(
|
||||
"initialize(address,address,uint256)",
|
||||
account,
|
||||
minter_,
|
||||
mintingAllowedAfter_
|
||||
)
|
||||
);
|
||||
|
||||
changeImplementationAfter = changeImplementationAfter_;
|
||||
|
||||
_setImplementation(implementation_);
|
||||
|
||||
minter = minter_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Called by the admin to update the implementation of the delegator
|
||||
* @param implementation_ The address of the new implementation for delegation
|
||||
*/
|
||||
function _setImplementation(address implementation_) public {
|
||||
require(msg.sender == minter, "TokenDelegator::_setImplementation: admin only");
|
||||
require(implementation_ != address(0), "TokenDelegator::_setImplementation: invalid implementation address");
|
||||
require(changeImplementationAfter >= block.timestamp, "TokenDelegator::_setImplementation: can change implementation changeImplementationAfter time only");
|
||||
|
||||
address oldImplementation = implementation;
|
||||
implementation = implementation_;
|
||||
|
||||
emit NewImplementation(oldImplementation, implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Internal method to delegate execution to another contract
|
||||
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
|
||||
* @param callee The contract to delegatecall
|
||||
* @param data The raw data to delegatecall
|
||||
*/
|
||||
function delegateTo(address callee, bytes memory data) internal {
|
||||
(bool success, bytes memory returnData) = callee.delegatecall(data);
|
||||
assembly {
|
||||
if eq(success, 0) {
|
||||
revert(add(returnData, 0x20), returndatasize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Delegates execution to an implementation contract.
|
||||
* It returns to the external caller whatever the implementation returns
|
||||
* or forwards reverts.
|
||||
*/
|
||||
fallback () external payable {
|
||||
// delegate all other functions to current implementation
|
||||
(bool success, ) = implementation.delegatecall(msg.data);
|
||||
|
||||
assembly {
|
||||
let free_mem_ptr := mload(0x40)
|
||||
returndatacopy(free_mem_ptr, 0, returndatasize())
|
||||
|
||||
switch success
|
||||
case 0 { revert(free_mem_ptr, returndatasize()) }
|
||||
default { return(free_mem_ptr, returndatasize()) }
|
||||
}
|
||||
}
|
||||
}
|
102
contracts/TokenInterfaces.sol
Normal file
102
contracts/TokenInterfaces.sol
Normal file
|
@ -0,0 +1,102 @@
|
|||
pragma solidity ^0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
interface TimelockInterface {
|
||||
function delay() external view returns (uint);
|
||||
function GRACE_PERIOD() external view returns (uint);
|
||||
function acceptAdmin() external;
|
||||
function queuedTransactions(bytes32 hash) external view returns (bool);
|
||||
function queueTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta) external returns (bytes32);
|
||||
function cancelTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta) external;
|
||||
function executeTransaction(address target, uint value, string calldata signature, bytes calldata data, uint eta) external payable returns (bytes memory);
|
||||
}
|
||||
|
||||
interface TokenInterface {
|
||||
function getPriorVotes(address account, uint blockNumber) external view returns (uint96);
|
||||
}
|
||||
|
||||
contract TokenEvents {
|
||||
|
||||
/// @notice An event thats emitted when an account changes its delegate
|
||||
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
|
||||
|
||||
/// @notice An event thats emitted when a delegate account's vote balance changes
|
||||
event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
|
||||
|
||||
/// @notice An event thats emitted when the minter changes
|
||||
event MinterChanged(address indexed oldMinter, address indexed newMinter);
|
||||
|
||||
/// @notice The standard EIP-20 transfer event
|
||||
event Transfer(address indexed from, address indexed to, uint256 amount);
|
||||
|
||||
/// @notice The standard EIP-20 approval event
|
||||
event Approval(address indexed owner, address indexed spender, uint256 amount);
|
||||
|
||||
/// @notice Emitted when implementation is changed
|
||||
event NewImplementation(address oldImplementation, address newImplementation);
|
||||
|
||||
/// @notice An event thats emitted when the token transfered is paused
|
||||
event TransferPaused(address minter);
|
||||
|
||||
/// @notice An event thats emitted when the token transfered is unpaused
|
||||
event TransferUnpaused(address minter);
|
||||
}
|
||||
|
||||
contract TokenDelegatorStorage {
|
||||
/// @notice Administrator Token minter
|
||||
address public minter;
|
||||
|
||||
/// @notice Active brains of Token
|
||||
address public implementation;
|
||||
|
||||
/// @notice The timestamp after which implementation maybe change
|
||||
uint public changeImplementationAfter;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @title Storage for Token Delegate
|
||||
* @notice For future upgrades, do not change TokenDelegateStorageV1. Create a new
|
||||
* contract which implements TokenDelegateStorageV1 and following the naming convention
|
||||
* TokenDelegateStorageVX.
|
||||
*/
|
||||
contract TokenDelegateStorageV1 is TokenDelegatorStorage {
|
||||
/// @notice EIP-20 token name for this token
|
||||
string public name = "<Token Name>"; // TODO - Replace it
|
||||
|
||||
/// @notice EIP-20 token symbol for this token
|
||||
string public symbol = "<TKN>"; // TODO - Replace it
|
||||
|
||||
/// @notice Total number of tokens in circulation
|
||||
uint public totalSupply = 10000000e18; // TODO - Replace it
|
||||
|
||||
/// @notice The timestamp after which minting may occur
|
||||
uint public mintingAllowedAfter;
|
||||
|
||||
// Allowance amounts on behalf of others
|
||||
mapping (address => mapping (address => uint96)) internal allowances;
|
||||
|
||||
// Official record of token balances for each account
|
||||
mapping (address => uint96) internal balances;
|
||||
|
||||
/// @notice A record of each accounts delegate
|
||||
mapping (address => address) public delegates;
|
||||
|
||||
/// @notice A checkpoint for marking number of votes from a given block
|
||||
struct Checkpoint {
|
||||
uint32 fromBlock;
|
||||
uint96 votes;
|
||||
}
|
||||
|
||||
/// @notice A record of votes checkpoints for each account, by index
|
||||
mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
|
||||
|
||||
/// @notice The number of checkpoints for each account
|
||||
mapping (address => uint32) public numCheckpoints;
|
||||
|
||||
/// @notice A record of states for signing / validating signatures
|
||||
mapping (address => uint) public nonces;
|
||||
|
||||
/// @notice token transfer pause state
|
||||
bool public transferPaused;
|
||||
}
|
17708
package-lock.json
generated
17708
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,7 @@
|
|||
"chai": "^4.3.4",
|
||||
"ethereum-waffle": "^3.3.0",
|
||||
"ethers": "^5.0.32",
|
||||
"hardhat": "^2.1.1"
|
||||
"hardhat": "^2.1.1",
|
||||
"solc": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user