diff --git a/.env.example b/.env.example index e69de29..c677c7b 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,3 @@ +ALCHEMY_ID="<>" +ETHERSCAN="<>" +PRIVATE_KEY="<>" \ No newline at end of file diff --git a/contracts/GovernorBravoDelegate.sol b/contracts/GovernorBravoDelegate.sol index e7f0b44..4e8ca22 100644 --- a/contracts/GovernorBravoDelegate.sol +++ b/contracts/GovernorBravoDelegate.sol @@ -9,15 +9,15 @@ import { } from "./GovernorBravoInterfaces.sol"; import { SafeMath } from "./SafeMath.sol"; -contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoEvents { +contract InstaGovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoEvents { /// @notice The name of this contract string public constant name = "DSL Governor Bravo"; /// @notice The minimum setable proposal threshold - uint public constant MIN_PROPOSAL_THRESHOLD = 50000e18; // TODO - Update this + uint public constant MIN_PROPOSAL_THRESHOLD = 500000e18; // 500,000 /// @notice The maximum setable proposal threshold - uint public constant MAX_PROPOSAL_THRESHOLD = 100000e18; // TODO - Update this + uint public constant MAX_PROPOSAL_THRESHOLD = 50000000e18; // 5,000,000 /// @notice The minimum setable voting period uint public constant MIN_VOTING_PERIOD = 5760; // About 24 hours @@ -32,7 +32,7 @@ contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoE uint public constant MAX_VOTING_DELAY = 40320; // About 1 week /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed - uint public constant quorumVotes = 400000e18; // TODO - Update this + uint public constant quorumVotes = 4000000e18; // 4,000,000 /// @notice The maximum number of actions that can be included in a proposal uint public constant proposalMaxOperations = 10; // 10 actions @@ -93,22 +93,6 @@ contract GovernorBravoDelegate is GovernorBravoDelegateStorageV1, GovernorBravoE uint endBlock = SafeMath.add(startBlock, votingPeriod); proposalCount++; - // Proposal memory newProposal = Proposal({ - // id: proposalCount, - // proposer: msg.sender, - // eta: 0, - // targets: targets, - // values: values, - // signatures: signatures, - // calldatas: calldatas, - // startBlock: startBlock, - // endBlock: endBlock, - // forVotes: 0, - // againstVotes: 0, - // abstainVotes: 0, - // canceled: false, - // executed: false - // }); Proposal storage newProposal = proposals[proposalCount]; diff --git a/contracts/GovernorBravoDelegator.sol b/contracts/GovernorBravoDelegator.sol index f6aa05f..fa2f89e 100644 --- a/contracts/GovernorBravoDelegator.sol +++ b/contracts/GovernorBravoDelegator.sol @@ -3,7 +3,7 @@ pragma experimental ABIEncoderV2; import { GovernorBravoDelegatorStorage, GovernorBravoEvents } from "./GovernorBravoInterfaces.sol"; -contract GovernorBravoDelegator is GovernorBravoDelegatorStorage, GovernorBravoEvents { +contract InstaGovernorBravoDelegator is GovernorBravoDelegatorStorage, GovernorBravoEvents { constructor( address timelock_, address admin_, diff --git a/contracts/Timelock.sol b/contracts/Timelock.sol index 35d95a8..8e5e87a 100644 --- a/contracts/Timelock.sol +++ b/contracts/Timelock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.7.0; import "./SafeMath.sol"; -contract Timelock { +contract InstaTimelock { using SafeMath for uint; event NewAdmin(address indexed newAdmin); diff --git a/contracts/TokenDelegate.sol b/contracts/TokenDelegate.sol index 9b9e89f..56a2ead 100644 --- a/contracts/TokenDelegate.sol +++ b/contracts/TokenDelegate.sol @@ -4,13 +4,12 @@ pragma experimental ABIEncoderV2; import { TokenDelegateStorageV1, TokenEvents} from "./TokenInterfaces.sol"; import { SafeMath } from "./SafeMath.sol"; -// TODO @thrilok209 @KaymasJain - Rename it -contract TokenDelegate is TokenDelegateStorageV1, TokenEvents { +contract InstaTokenDelegate is TokenDelegateStorageV1, TokenEvents { /// @notice Minimum time between mints - uint32 public constant minimumTimeBetweenMints = 1 days * 7; // TODO @thrilok209 @KaymasJain - Replace it + uint32 public constant minimumTimeBetweenMints = 1 days * 365; // 365 days /// @notice Cap on the percentage of totalSupply that can be minted at each mint - uint8 public constant mintCap = 2; // TODO @thrilok209 @KaymasJain - Replace it + uint8 public constant mintCap = 2; // 2% /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); diff --git a/contracts/TokenDelegator.sol b/contracts/TokenDelegator.sol index 5061b9c..aeba864 100644 --- a/contracts/TokenDelegator.sol +++ b/contracts/TokenDelegator.sol @@ -3,13 +3,12 @@ pragma experimental ABIEncoderV2; import { TokenDelegatorStorage, TokenEvents } from "./TokenInterfaces.sol"; -contract TokenDelegator is TokenDelegatorStorage, TokenEvents { +contract InstaToken is TokenDelegatorStorage, TokenEvents { constructor( address account, address implementation_, uint initialSupply_, uint mintingAllowedAfter_, - uint changeImplementationAfter_, bool transferPaused_ ) { require(implementation_ != address(0), "TokenDelegator::constructor invalid address"); @@ -26,8 +25,6 @@ contract TokenDelegator is TokenDelegatorStorage, TokenEvents { implementation = implementation_; - changeImplementationAfter = changeImplementationAfter_; - emit NewImplementation(address(0), implementation); } @@ -37,7 +34,6 @@ contract TokenDelegator is TokenDelegatorStorage, TokenEvents { */ function _setImplementation(address implementation_) external isMaster { require(implementation_ != address(0), "TokenDelegator::_setImplementation: invalid implementation address"); - require(block.timestamp >= changeImplementationAfter, "TokenDelegator::_setImplementation: can change implementation changeImplementationAfter time only"); address oldImplementation = implementation; implementation = implementation_; diff --git a/contracts/TokenInterfaces.sol b/contracts/TokenInterfaces.sol index 8d8ae50..dfab978 100644 --- a/contracts/TokenInterfaces.sol +++ b/contracts/TokenInterfaces.sol @@ -39,19 +39,17 @@ contract TokenEvents { } contract TokenDelegatorStorage { + /// @notice InstaIndex contract IndexInterface constant public instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); /// @notice Active brains of Token address public implementation; - /// @notice The timestamp after which implementation maybe change - uint public changeImplementationAfter; - /// @notice EIP-20 token name for this token - string public name = ""; // TODO - Replace it + string public name = "Instadapp"; /// @notice EIP-20 token symbol for this token - string public symbol = ""; // TODO - Replace it + string public symbol = "INST"; /// @notice Total number of tokens in circulation uint public totalSupply; diff --git a/hardhat.config.js b/hardhat.config.js index e973b1f..915b49e 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -4,6 +4,7 @@ require("@nomiclabs/hardhat-etherscan"); require("dotenv").config(); const ALCHEMY_ID = process.env.ALCHEMY_ID; +const PRIVATE_KEY = process.env.PRIVATE_KEY; // You need to export an object to set up your config // Go to https://hardhat.org/config/ to learn more @@ -13,7 +14,15 @@ const ALCHEMY_ID = process.env.ALCHEMY_ID; */ module.exports = { defaultNetwork: "hardhat", - solidity: "0.7.3", + solidity: { + version: "0.7.3", + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + }, networks: { hardhat: { forking: { @@ -22,9 +31,13 @@ module.exports = { }, blockGasLimit: 12000000, }, + kovan: { + url: `https://eth-kovan.alchemyapi.io/v2/${ALCHEMY_ID}`, + accounts: [`0x${PRIVATE_KEY}`], + gas: 12500000, + }, }, etherscan: { apiKey: process.env.ETHERSCAN } }; - diff --git a/package-lock.json b/package-lock.json index 4c755cd..1782caa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "license": "ISC", "dependencies": { "@nomiclabs/hardhat-etherscan": "^2.1.1", - "dotenv": "^8.2.0" + "dotenv": "^8.2.0", + "rlp": "^2.2.6" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.0.2", diff --git a/package.json b/package.json index dcf90bd..be53d29 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ }, "dependencies": { "@nomiclabs/hardhat-etherscan": "^2.1.1", - "dotenv": "^8.2.0" + "dotenv": "^8.2.0", + "rlp": "^2.2.6" } } diff --git a/scripts/deploy.js b/scripts/deploy.js new file mode 100644 index 0000000..dae34c1 --- /dev/null +++ b/scripts/deploy.js @@ -0,0 +1,100 @@ +const hre = require("hardhat"); +const RLP = require('rlp'); +const { ethers } = hre; + +async function main() { + const deployerAddress = '0xf6839085F692bDe6A8062573E3DA35E7e947C21E' + const initialSupply = ethers.utils.parseEther("100000000") // 100M supply + const initialHolder = '0xb1DC62EC38E6E3857a887210C38418E4A17Da5B2' + const mintingAfter = 1704067200 // Monday, 1 January 2024 00:00:00 + const votingPeriod = 17280 // ~3 days in blocks (assuming 15s blocks) + const votingDelay = 1 // 1 block + const proposalThreshold = ethers.utils.parseEther("1000000") // 1M + const timelockDelay = 172800 // ~2 days in blocks (assuming 15s blocks) + + const TokenDelegate = await ethers.getContractFactory("InstaTokenDelegate") + const tokenDelegate = await TokenDelegate.deploy() + + await tokenDelegate.deployed() + + const TokenDelegator = await ethers.getContractFactory("InstaToken") + const tokenDelegator = await TokenDelegator + .deploy(initialHolder, tokenDelegate.address, initialSupply, mintingAfter, false) + + await tokenDelegator.deployed() + + const txCount = await ethers.provider.getTransactionCount(deployerAddress) + 2 + + const timelockAddress = '0x' + ethers.utils.keccak256(RLP.encode([deployerAddress, txCount])).slice(12).substring(14) + + const GovernorDelegate = await ethers.getContractFactory("InstaGovernorBravoDelegate") + const governorDelegate = await GovernorDelegate.deploy() + + await governorDelegate.deployed() + + const GovernorDelegator = await ethers.getContractFactory("InstaGovernorBravoDelegator") + const governorDelegator = await GovernorDelegator + .deploy( + timelockAddress, + timelockAddress, + tokenDelegator.address, + governorDelegate.address, + votingPeriod, + votingDelay, + proposalThreshold + ) + + await governorDelegator.deployed() + + const Timelock = await ethers.getContractFactory("InstaTimelock") + const timelock = await Timelock.deploy(governorDelegator.address, timelockDelay) + + await timelock.deployed() + + console.log("InstaTokenDelegate: ", tokenDelegate.address) + console.log("InstaToken: ", tokenDelegator.address) + console.log("InstaTimelock: ", timelock.address) + console.log("InstaGovernorBravoDelegate: ", governorDelegate.address) + console.log("InstaGovernorBravoDelegator: ", governorDelegator.address) + console.log() + + await hre.run("verify:verify", { + address: tokenDelegate.address, + constructorArguments: [] + }) + + await hre.run("verify:verify", { + address: tokenDelegator.address, + constructorArguments: [initialHolder, tokenDelegate.address, initialSupply, mintingAfter, false] + }) + + await hre.run("verify:verify", { + address: governorDelegate.address, + constructorArguments: [] + }) + + await hre.run("verify:verify", { + address: governorDelegator.address, + constructorArguments: [ + timelockAddress, + timelockAddress, + tokenDelegator.address, + governorDelegate.address, + votingPeriod, + votingDelay, + proposalThreshold + ] + }) + + await hre.run("verify:verify", { + address: timelock.address, + constructorArguments: [governorDelegator.address, timelockDelay] + }) +} + +main() + .then(() => process.exit(0)) + .catch(error => { + console.error(error); + process.exit(1); + });