diff --git a/.env.sample b/.env.sample index fe4f6de..76c51f3 100644 --- a/.env.sample +++ b/.env.sample @@ -1,5 +1,5 @@ -ALCHEMY_API_KEY=OC1jcFclXkR7LbjMUSfSP-v08nbbhsFF -INFURA_KEY=fc92f5e472a3467cb8b9abd6d0aca04b +ALCHEMY_API_KEY= +INFURA_KEY= ; if PRIVATE_KEY is set mnemonic will be ignored PRIVATE_KEY= MNEMONIC= diff --git a/contracts/MeTokens.sol b/contracts/ME.sol similarity index 74% rename from contracts/MeTokens.sol rename to contracts/ME.sol index a94eb34..7dbd600 100644 --- a/contracts/MeTokens.sol +++ b/contracts/ME.sol @@ -9,15 +9,20 @@ import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft- import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; -/// @title meTokens erc20 contract (ME) -/// @author @CBobRobison, @cartercarlson, @cryptounico +/// @title meTokens erc20 governance contract (ME) +/// @author @CBobRobison, @cartercarlson, @parvgarg, @zgorrizzo69, @cryptounico /// @notice Base erc20 token used for meTokens protocol governance -contract MeTokens is ERC20Votes, ERC20Snapshot, ERC20Burnable, Ownable { +contract ME is ERC20Votes, ERC20Snapshot, ERC20Burnable, Ownable { uint256 public constant PRECISION = 1e18; uint256 public constant MAX_PCT_MINTABLE = 5 * 1e16; // 5% uint256 public lastMintTimestamp; uint256 public lastMintPct; + /** + * @dev Constructor. + * @param name The name for this token. + * @param symbol The symbol for this token. + */ constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) @@ -26,9 +31,13 @@ contract MeTokens is ERC20Votes, ERC20Snapshot, ERC20Burnable, Ownable { lastMintTimestamp = block.timestamp; } + /// @notice Mint new tokens, up to a rate of 5% of supply per rolling year + /// @param account Address to receive the minted ME + /// @param pctMint Percentage of supply to mint where 1e18 is 100% + /// @param max True if minting the max permitted function mint( address account, - uint256 _pctMint, + uint256 pctMint, bool max ) external onlyOwner { uint256 pctMintable = getPctMintable(); @@ -37,21 +46,23 @@ contract MeTokens is ERC20Votes, ERC20Snapshot, ERC20Burnable, Ownable { if (max) { amount = (totalSupply() * pctMintable) / PRECISION; } else { - require(_pctMint <= pctMintable, "amount exceeds max"); - require(_pctMint != 0, "_pctMint == 0"); - amount = (totalSupply() * _pctMint) / PRECISION; + require(pctMint <= pctMintable, "amount exceeds max"); + require(pctMint != 0, "pctMint == 0"); + amount = (totalSupply() * pctMint) / PRECISION; } - lastMintPct = pctMintable - _pctMint; + lastMintPct = pctMintable - pctMint; lastMintTimestamp = block.timestamp; _mint(account, amount); } + /// @notice Returns the chain id used by this contract. function getChainId() external view returns (uint256) { return block.chainid; } + /// @notice Get the percent of supply that can be minted at the current timestamp function getPctMintable() public view returns (uint256) { uint256 period = block.timestamp - lastMintTimestamp; uint256 pctOfYear = (PRECISION * period) / 365 days; diff --git a/scripts/deploy.ts b/scripts/deploy.ts index bbeff47..559fbdb 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -1,5 +1,5 @@ import { deploy } from "../test/utils/helpers"; -import { MeTokens } from "../artifacts/types"; +import { ME } from "../artifacts/types"; import { ethers, network } from "hardhat"; import fs from "fs"; import { verifyContract } from "./utils"; @@ -14,19 +14,19 @@ async function main() { const constructorParams = ["meTokens", "ME"]; // deploy erc20 contract - let meTokens = await deploy( - "MeTokens", + let me = await deploy( + "ME", undefined, constructorParams[0], constructorParams[1] ); - console.log(`MeTokens deployed at ${meTokens.address}`); + console.log(`ME deployed at ${me.address}`); const deploymentInfo = { deployer: deployer.address, owner: deployer.address, chainId, - meTokensContract: meTokens.address, + meContract: me.address, }; console.log("Deployment Info: ", deploymentInfo); @@ -36,13 +36,12 @@ async function main() { JSON.stringify(deploymentInfo, undefined, 2) ); - // TODO can also add mainnet here - if (network.name === "rinkeby") { + if (network.name === "rinkeby" || network.name === "mainnet") { console.log( "wait for 5 blocks until bytecodes are uploaded into etherscan" ); - await meTokens.deployTransaction.wait(5); - await verifyContract("MeTokens", meTokens.address, constructorParams); + await me.deployTransaction.wait(5); + await verifyContract("ME", me.address, constructorParams); } } diff --git a/test/MeTokens.ts b/test/ME.ts similarity index 94% rename from test/MeTokens.ts rename to test/ME.ts index b9d0acd..e19e9af 100644 --- a/test/MeTokens.ts +++ b/test/ME.ts @@ -4,7 +4,7 @@ import { expect } from "chai"; import { BigNumber } from "ethers"; import { mineBlock, setAutomine } from "./utils/hardhatNode"; import { deploy, fromETHNumber } from "./utils/helpers"; -import { MeTokens } from "../artifacts/types"; +import { ME } from "../artifacts/types"; const calGetPctMintable = async ( timestamp: BigNumber, @@ -29,19 +29,14 @@ const setup = async () => { const ONE_PCT = fromETHNumber(0.01); const RANDOM_PCT = fromETHNumber(0.0000069); const PRECISION = fromETHNumber(1); - let meTokens: MeTokens; + let meTokens: ME; let account0: SignerWithAddress; let account1: SignerWithAddress; let account2: SignerWithAddress; - describe("MeTokens.sol", () => { + describe("ME.sol", () => { before(async () => { [account0, account1, account2] = await ethers.getSigners(); - meTokens = await deploy( - "MeTokens", - undefined, - "meTokens", - "ME" - ); + meTokens = await deploy("ME", undefined, "meTokens", "ME"); }); it("Correct initial state", async () => { @@ -102,7 +97,7 @@ const setup = async () => { it("Cannot mint 0", async () => { const tx = meTokens.mint(account2.address, 0, false); - await expect(tx).to.be.revertedWith("_pctMint == 0"); + await expect(tx).to.be.revertedWith("pctMint == 0"); }); it("Owner cannot mint more than mintable supply", async () => {