mirror of
https://github.com/Instadapp/dsa-governance.git
synced 2024-07-29 22:27:52 +00:00
commit
b5d4dc74e6
0
.env.example
Normal file
0
.env.example
Normal file
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,3 +3,5 @@ node_modules
|
||||||
#Hardhat files
|
#Hardhat files
|
||||||
cache
|
cache
|
||||||
artifacts
|
artifacts
|
||||||
|
|
||||||
|
.env
|
|
@ -1,54 +1,16 @@
|
||||||
pragma solidity ^0.7.0;
|
pragma solidity ^0.7.0;
|
||||||
pragma experimental ABIEncoderV2;
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import { TokenDelegateStorageV1, TokenEvents} from "./TokenInterfaces.sol";
|
||||||
import { SafeMath } from "./SafeMath.sol";
|
import { SafeMath } from "./SafeMath.sol";
|
||||||
|
|
||||||
// TODO - Rename it
|
// TODO @thrilok209 @KaymasJain - Rename it
|
||||||
contract Token {
|
contract TokenDelegate is TokenDelegateStorageV1, TokenEvents {
|
||||||
/// @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
|
|
||||||
|
|
||||||
/// @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
|
/// @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
|
/// @notice Cap on the percentage of totalSupply that can be minted at each mint
|
||||||
uint8 public constant mintCap = 2; // TODO - Replace it
|
uint8 public constant mintCap = 2; // TODO @thrilok209 @KaymasJain - 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;
|
|
||||||
|
|
||||||
/// @notice The EIP-712 typehash for the contract's domain
|
/// @notice The EIP-712 typehash for the contract's domain
|
||||||
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
|
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
|
||||||
|
@ -59,42 +21,72 @@ contract Token {
|
||||||
/// @notice The EIP-712 typehash for the permit struct used by the contract
|
/// @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)");
|
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 Used to initialize the contract during delegator constructor
|
||||||
|
* @param account The address to recieve initial suppply
|
||||||
|
* @param mintingAllowedAfter_ Timestamp of the next allowed minting
|
||||||
|
* @param transferPaused_ Flag to make the token non-transferable
|
||||||
|
*/
|
||||||
|
function initialize(address account, uint initialSupply_, uint mintingAllowedAfter_, bool transferPaused_) public {
|
||||||
|
require(mintingAllowedAfter == 0, "Token::initialize: can only initialize once");
|
||||||
|
require(totalSupply == 0, "Token::initialize: can only initialize once");
|
||||||
|
require(mintingAllowedAfter_ >= block.timestamp, "Token::constructor: minting can only begin after deployment");
|
||||||
|
require(account != address(0), "Token::initialize: invalid address");
|
||||||
|
require(initialSupply_ > 0, "Token::initialize: invalid initial supply");
|
||||||
|
|
||||||
/// @notice An event thats emitted when a delegate account's vote balance changes
|
totalSupply = initialSupply_;
|
||||||
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");
|
|
||||||
|
|
||||||
balances[account] = uint96(totalSupply);
|
balances[account] = uint96(totalSupply);
|
||||||
emit Transfer(address(0), account, totalSupply);
|
emit Transfer(address(0), account, totalSupply);
|
||||||
minter = minter_;
|
|
||||||
emit MinterChanged(address(0), minter);
|
|
||||||
mintingAllowedAfter = mintingAllowedAfter_;
|
mintingAllowedAfter = mintingAllowedAfter_;
|
||||||
|
transferPaused = transferPaused_;
|
||||||
|
|
||||||
|
if (transferPaused) {
|
||||||
|
emit TransferPaused(msg.sender);
|
||||||
|
} else {
|
||||||
|
emit TransferUnpaused(msg.sender);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice Change the minter address
|
* @notice Pause the token transfer
|
||||||
* @param minter_ The address of the new minter
|
|
||||||
*/
|
*/
|
||||||
function setMinter(address minter_) external {
|
function pauseTransfer() external isMaster {
|
||||||
require(msg.sender == minter, "Tkn::setMinter: only the minter can change the minter address");
|
transferPaused = true;
|
||||||
emit MinterChanged(minter, minter_);
|
emit TransferPaused(msg.sender);
|
||||||
minter = minter_;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Unpause the token transfer
|
||||||
|
*/
|
||||||
|
function unpauseTransfer() external isMaster {
|
||||||
|
transferPaused = false;
|
||||||
|
emit TransferUnpaused(msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Change token name
|
||||||
|
* @param name_ New token name
|
||||||
|
*/
|
||||||
|
function changeName(string calldata name_) external isMaster {
|
||||||
|
require(bytes(name_).length > 0, "Tkn::changeName: name_ length invaild");
|
||||||
|
|
||||||
|
emit ChangedName(name, name_);
|
||||||
|
|
||||||
|
name = name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice Change token symbol
|
||||||
|
* @param symbol_ New token symbol
|
||||||
|
*/
|
||||||
|
function changeSymbol(string calldata symbol_) external isMaster {
|
||||||
|
require(bytes(symbol_).length > 0, "Tkn::changeSymbol: name_name_ length invaild");
|
||||||
|
|
||||||
|
emit ChangedName(symbol, symbol_);
|
||||||
|
|
||||||
|
symbol = symbol_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -209,8 +201,7 @@ contract Token {
|
||||||
* @param dst The address of the destination account
|
* @param dst The address of the destination account
|
||||||
* @param rawAmount The number of tokens to be minted
|
* @param rawAmount The number of tokens to be minted
|
||||||
*/
|
*/
|
||||||
function mint(address dst, uint rawAmount) external {
|
function mint(address dst, uint rawAmount) external isMaster {
|
||||||
require(msg.sender == minter, "Tkn::mint: only the minter can mint");
|
|
||||||
require(block.timestamp >= mintingAllowedAfter, "Uni::mint: minting not allowed yet");
|
require(block.timestamp >= mintingAllowedAfter, "Uni::mint: minting not allowed yet");
|
||||||
require(dst != address(0), "Tkn::mint: cannot transfer to the zero address");
|
require(dst != address(0), "Tkn::mint: cannot transfer to the zero address");
|
||||||
|
|
||||||
|
@ -321,6 +312,7 @@ contract Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
function _transferTokens(address src, address dst, uint96 amount) internal {
|
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(src != address(0), "Tkn::_transferTokens: cannot transfer from the zero address");
|
||||||
require(dst != address(0), "Tkn::_transferTokens: cannot transfer to the zero address");
|
require(dst != address(0), "Tkn::_transferTokens: cannot transfer to the zero address");
|
||||||
|
|
81
contracts/TokenDelegator.sol
Normal file
81
contracts/TokenDelegator.sol
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
pragma solidity ^0.7.0;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
import { TokenDelegatorStorage, TokenEvents } from "./TokenInterfaces.sol";
|
||||||
|
|
||||||
|
contract TokenDelegator is TokenDelegatorStorage, TokenEvents {
|
||||||
|
constructor(
|
||||||
|
address account,
|
||||||
|
address implementation_,
|
||||||
|
uint initialSupply_,
|
||||||
|
uint mintingAllowedAfter_,
|
||||||
|
uint changeImplementationAfter_,
|
||||||
|
bool transferPaused_
|
||||||
|
) {
|
||||||
|
require(implementation_ != address(0), "TokenDelegator::constructor invalid address");
|
||||||
|
delegateTo(
|
||||||
|
implementation_,
|
||||||
|
abi.encodeWithSignature(
|
||||||
|
"initialize(address,uint256,uint256,bool)",
|
||||||
|
account,
|
||||||
|
initialSupply_,
|
||||||
|
mintingAllowedAfter_,
|
||||||
|
transferPaused_
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
implementation = implementation_;
|
||||||
|
|
||||||
|
changeImplementationAfter = changeImplementationAfter_;
|
||||||
|
|
||||||
|
emit NewImplementation(address(0), implementation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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_) 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_;
|
||||||
|
|
||||||
|
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()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
contracts/TokenInterfaces.sol
Normal file
104
contracts/TokenInterfaces.sol
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
pragma solidity ^0.7.0;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
interface IndexInterface {
|
||||||
|
function master() external view returns (address);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 indexed minter);
|
||||||
|
|
||||||
|
/// @notice An event thats emitted when the token transfered is unpaused
|
||||||
|
event TransferUnpaused(address indexed minter);
|
||||||
|
|
||||||
|
/// @notice An event thats emitted when the token symbol is changed
|
||||||
|
event ChangedSymbol(string oldSybmol, string newSybmol);
|
||||||
|
|
||||||
|
/// @notice An event thats emitted when the token name is changed
|
||||||
|
event ChangedName(string oldName, string newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract TokenDelegatorStorage {
|
||||||
|
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 = "<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;
|
||||||
|
|
||||||
|
/// @notice EIP-20 token decimals for this token
|
||||||
|
uint8 public constant decimals = 18;
|
||||||
|
|
||||||
|
modifier isMaster() {
|
||||||
|
require(instaIndex.master() == msg.sender, "Tkn::isMaster: msg.sender not master");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 The timestamp after which minting may occur
|
||||||
|
uint public mintingAllowedAfter;
|
||||||
|
|
||||||
|
/// @notice token transfer pause state
|
||||||
|
bool public transferPaused;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
|
@ -1,14 +1,9 @@
|
||||||
|
require("@nomiclabs/hardhat-ethers");
|
||||||
require("@nomiclabs/hardhat-waffle");
|
require("@nomiclabs/hardhat-waffle");
|
||||||
|
require("@nomiclabs/hardhat-etherscan");
|
||||||
|
|
||||||
// This is a sample Hardhat task. To learn how to create your own go to
|
require("dotenv").config();
|
||||||
// https://hardhat.org/guides/create-task.html
|
const ALCHEMY_ID = process.env.ALCHEMY_ID;
|
||||||
task("accounts", "Prints the list of accounts", async () => {
|
|
||||||
const accounts = await ethers.getSigners();
|
|
||||||
|
|
||||||
for (const account of accounts) {
|
|
||||||
console.log(account.address);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// You need to export an object to set up your config
|
// You need to export an object to set up your config
|
||||||
// Go to https://hardhat.org/config/ to learn more
|
// Go to https://hardhat.org/config/ to learn more
|
||||||
|
@ -17,6 +12,19 @@ task("accounts", "Prints the list of accounts", async () => {
|
||||||
* @type import('hardhat/config').HardhatUserConfig
|
* @type import('hardhat/config').HardhatUserConfig
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
defaultNetwork: "hardhat",
|
||||||
solidity: "0.7.3",
|
solidity: "0.7.3",
|
||||||
|
networks: {
|
||||||
|
hardhat: {
|
||||||
|
forking: {
|
||||||
|
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`,
|
||||||
|
blockNumber: 12070498,
|
||||||
|
},
|
||||||
|
blockGasLimit: 12000000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
etherscan: {
|
||||||
|
apiKey: process.env.ETHERSCAN
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
7095
package-lock.json
generated
7095
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,11 @@
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"ethereum-waffle": "^3.3.0",
|
"ethereum-waffle": "^3.3.0",
|
||||||
"ethers": "^5.0.32",
|
"ethers": "^5.0.32",
|
||||||
"hardhat": "^2.1.1"
|
"hardhat": "^2.1.1",
|
||||||
|
"solc": "^0.7.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nomiclabs/hardhat-etherscan": "^2.1.1",
|
||||||
|
"dotenv": "^8.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
// We require the Hardhat Runtime Environment explicitly here. This is optional
|
|
||||||
// but useful for running the script in a standalone fashion through `node <script>`.
|
|
||||||
//
|
|
||||||
// When running the script with `hardhat run <script>` you'll find the Hardhat
|
|
||||||
// Runtime Environment's members available in the global scope.
|
|
||||||
const hre = require("hardhat");
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
// Hardhat always runs the compile task when running scripts with its command
|
|
||||||
// line interface.
|
|
||||||
//
|
|
||||||
// If this script is run directly using `node` you may want to call compile
|
|
||||||
// manually to make sure everything is compiled
|
|
||||||
// await hre.run('compile');
|
|
||||||
|
|
||||||
// We get the contract to deploy
|
|
||||||
const Greeter = await hre.ethers.getContractFactory("Greeter");
|
|
||||||
const greeter = await Greeter.deploy("Hello, Hardhat!");
|
|
||||||
|
|
||||||
await greeter.deployed();
|
|
||||||
|
|
||||||
console.log("Greeter deployed to:", greeter.address);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We recommend this pattern to be able to use async/await everywhere
|
|
||||||
// and properly handle errors.
|
|
||||||
main()
|
|
||||||
.then(() => process.exit(0))
|
|
||||||
.catch(error => {
|
|
||||||
console.error(error);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
|
@ -1,14 +0,0 @@
|
||||||
const { expect } = require("chai");
|
|
||||||
|
|
||||||
describe("Greeter", function() {
|
|
||||||
it("Should return the new greeting once it's changed", async function() {
|
|
||||||
const Greeter = await ethers.getContractFactory("Greeter");
|
|
||||||
const greeter = await Greeter.deploy("Hello, world!");
|
|
||||||
|
|
||||||
await greeter.deployed();
|
|
||||||
expect(await greeter.greet()).to.equal("Hello, world!");
|
|
||||||
|
|
||||||
await greeter.setGreeting("Hola, mundo!");
|
|
||||||
expect(await greeter.greet()).to.equal("Hola, mundo!");
|
|
||||||
});
|
|
||||||
});
|
|
103
test/token.test.js
Normal file
103
test/token.test.js
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
const hre = require("hardhat");
|
||||||
|
const { expect } = require("chai");
|
||||||
|
const { ethers, network } = hre;
|
||||||
|
|
||||||
|
describe("Token", function() {
|
||||||
|
let tokenDelegate, tokenDelegator, token, masterAddress, minter, account0, account1, account2, account3, initialSupply, allowedAfter, ethereum
|
||||||
|
before(async () => {
|
||||||
|
masterAddress = "0xb1DC62EC38E6E3857a887210C38418E4A17Da5B2"
|
||||||
|
await hre.network.provider.request({
|
||||||
|
method: "hardhat_impersonateAccount",
|
||||||
|
params: [ masterAddress ]
|
||||||
|
})
|
||||||
|
accounts = await ethers.getSigners()
|
||||||
|
minter = ethers.provider.getSigner(masterAddress)
|
||||||
|
|
||||||
|
account0 = accounts[0]
|
||||||
|
account1 = accounts[1]
|
||||||
|
account2 = accounts[2]
|
||||||
|
account3 = accounts[3]
|
||||||
|
|
||||||
|
const TokenDelegate = await ethers.getContractFactory("TokenDelegate")
|
||||||
|
tokenDelegate = await TokenDelegate.deploy()
|
||||||
|
|
||||||
|
await tokenDelegate.deployed()
|
||||||
|
|
||||||
|
allowedAfter = 1622505601 // June 1 2021
|
||||||
|
|
||||||
|
initialSupply = ethers.utils.parseEther("1000000000")
|
||||||
|
|
||||||
|
const TokenDelegator = await ethers.getContractFactory("TokenDelegator")
|
||||||
|
tokenDelegator = await TokenDelegator
|
||||||
|
.deploy(account0.address, tokenDelegate.address, initialSupply, allowedAfter, allowedAfter, false)
|
||||||
|
|
||||||
|
await tokenDelegator.deployed()
|
||||||
|
|
||||||
|
token = await ethers.getContractAt("TokenDelegate", tokenDelegator.address)
|
||||||
|
|
||||||
|
await token.transfer(account1.address, ethers.utils.parseEther("10000"))
|
||||||
|
await token.transfer(account2.address, ethers.utils.parseEther("20000"))
|
||||||
|
|
||||||
|
ethereum = network.provider
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should match the deployed", async () => {
|
||||||
|
const totalSupply_ = await token.totalSupply()
|
||||||
|
const transferPaused_ = await token.transferPaused()
|
||||||
|
const name_ = await token.name()
|
||||||
|
const symbol_ = await token.symbol()
|
||||||
|
expect(totalSupply_).to.be.equal(initialSupply)
|
||||||
|
expect(transferPaused_).to.be.equal(false)
|
||||||
|
expect(name_).to.be.equal("<Token Name>")
|
||||||
|
expect(symbol_).to.be.equal("<TKN>")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should pause transfer", async () => {
|
||||||
|
await token.connect(minter).pauseTransfer()
|
||||||
|
const transferPaused_ = await token.transferPaused()
|
||||||
|
expect(transferPaused_).to.be.equal(true)
|
||||||
|
await expect(token.transfer(account1.address, ethers.utils.parseEther("10000")))
|
||||||
|
.to.be.revertedWith("Tkn::_transferTokens: transfer paused")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should unpause transfer", async () => {
|
||||||
|
await token.connect(minter).unpauseTransfer()
|
||||||
|
const transferPaused_ = await token.transferPaused()
|
||||||
|
expect(transferPaused_).to.be.equal(false)
|
||||||
|
await token.transfer(account3.address, ethers.utils.parseEther("10"))
|
||||||
|
const balance = await token.balanceOf(account3.address)
|
||||||
|
expect(balance).to.be.equal(ethers.utils.parseEther("10"))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should change name", async () => {
|
||||||
|
await token.connect(minter).changeName("Awesome Token")
|
||||||
|
const name_ = await token.name()
|
||||||
|
expect(name_).to.be.equal("Awesome Token")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should change symbol", async () => {
|
||||||
|
await token.connect(minter).changeSymbol("AWT")
|
||||||
|
const name_ = await token.symbol()
|
||||||
|
expect(name_).to.be.equal("AWT")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should delegate", async () => {
|
||||||
|
await token.connect(account1).delegate(account3.address)
|
||||||
|
const delegate_ = await token.delegates(account1.address)
|
||||||
|
expect(delegate_).to.be.equal(account3.address)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Should mint after allowed time", async () => {
|
||||||
|
await ethereum.send("evm_setNextBlockTimestamp", [allowedAfter+100])
|
||||||
|
await ethereum.send("evm_mine", [])
|
||||||
|
|
||||||
|
const mintAmount = ethers.utils.parseEther("1000")
|
||||||
|
|
||||||
|
await token.connect(minter).mint(account2.address, mintAmount)
|
||||||
|
|
||||||
|
const newTotalSupply = initialSupply.add(mintAmount)
|
||||||
|
|
||||||
|
const totalSupply_ = await token.totalSupply()
|
||||||
|
expect(totalSupply_).to.be.equal(newTotalSupply)
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user