- Dependencies
- Installation
- Additional Packages
- Folder & File Structure
- Draft Contract
- Version Control
- Post Contract & Test Development Steps
- Contract List
- Contracts
- Utility Contracts
- Contract Interfaces
IERC721Burnable
IERC721Minable
IERC721MinterBurnable
IRandomNumberGenerator
OpenZeppelin Version: ^4.3.3
Solidity Version: ^0.8.0
Clone the repository as submodule and place it in the ~/contracts/library directory
⚠️ Always remove the artifacts and cache directory when use it as a submodule⚠️
- python3 & pip3
brew install python3
- solc-select
pip3 install solc-select
To install slither
pip3 install slither-analyzer
Install the version of solidity compiler
solc-select install {version}
e.g.
solc-select install 0.8.4
Implement the wanted version
solc-select use {version}
e.g.
solc-select use 0.8.4
Run static analysis with slither
yarn run slither
.
├── contracts # Contracts folder
│ ├── interfaces # Interface contracts
│ ├── mocks # Mock contracts for testing
│ ├── utils # Utility contracts
│ └── ...
├── test # Test scripts folder
│ ├── helper.js # Test helper functions for testing
│ └── ... # Test files with *.test.js
└── ...
For any unfinished contract, please name it with the prefix draft-
.
e.g.
draft-Contract.sol
The prefix draft-
should be deleted only after test cases were completed with 100% coverage and confirmed it is bug-free.
Please be aware that new version of a contract should be created if any change is wanted to be made to a deployed contract with Vn
while n is the version number
e.g.
Payable.sol to PayableV2.sol as Payable.sol has been deployed in other project
New version of PayableV2.sol will be PayableV3.sol, PayableV4.sol, PayableV5.sol, ...
npx hardhat coverage
# with harthat-shorthand installed
hh coverage
yarn run slither
IERC721Burnable
IERC721Minable
IERC721MinterBurnable
IRandomNumberGenerator
Contract
Vesting contract that supports single ERC20 that linearly distributes tokens over time. Each address can contain its own vesting schedule including the start time, duration, cliff duration and amount of tokens.
- Deploy the contract with the vesting token address
- Transfer sufficient amount of vesting token to the contract
- Use
addVesting
to add a vesting wallet to the contract
Contract
Random number generator contract that implements the Chainlink Oracle Service's Verifiable Random Function
- Create a subscription to Chainlink VRF in the target chain
- Fund the subscription with $LINK
- Get the
vrfCoordinator
address andkeyHash
of the target chain in Chainlink docs - Deploy the contract with the following parameters:
subcriptionId
: the subscription ID of the target chain created at Chainlink VRFvrfCoordinator
: the address of the VRF coordinatorkeyHash
: the key hash of the target chain
- Copy the deployed
VRFRandomNumberGenerator
address and add it as a consumer in the created subscription in Chainlink VRF - Run
requestRandomWords
function to fill up the first queue - Always make sure the subscription is funded with $LINK
Utility Contract
Utility contract that provides functions for payment control for both native tokens and ERC20 tokens with 1 fee receiver
Extends with
import "./library/contracts/utils/Payable.sol";
contract Contract is Payable {
constructor (
address payable _feeReceiver
)
Payable(_feeReceiver)
{
// ...
}
}
Switch between native token and ERC20 token
// Run following functions with owner account
const erc20 = await ethers.getContract('Erc20')
await contract.setIsErc20(erc20.address)
await contract.setIsNonErc20()
Payment
// Run following function in contract
function fn(uint256 _amount) public payable {
pay(_amount);
// ...
}
Utility Contract
Utility contract that provides functions for staking period control, including staking period start, end and reward end time in both block.timestamp
and block.number
measures
Extends with
import "./library/contracts/utils/StakingPeriodControl.sol";
contract Contract is StakingPeriodControl {
# instead of setting up with constructor, additional initailize() function should be used
function initialize(
uint256 _isTimestamp,
uint256 _start,
uint256 _end,
uint256 _bonusEnd
) {
__StakingPeriodControl__init(_isTimestamp, _start, _end, _bonusEnd);
}
}
Provided modifiers
beforeStakeStart
afterStakeStart
beforeStakeEnd
afterStakeEnd
beforeBonusEnd
afterBonusEnd
Utility Contract
Utility contract that provides functions for whitelist control with merkle tree implementation
Extends with
import "./library/contracts/utils/Whitelist.sol";
contract Contract is Whitelist {
// ...
}
Provided modifier
onlyWhitelisted(bytes32[] memory proof)
// Contract level implementation
function fn(bytes32[] memory _proof) public onlyWhitelisted(_proof) {
// ...
}
To add whitelist
const keccal256 = require('keccak256')
const { MerkleTree } = require('merkletreejs')
const addresses = [...]
const tree = new MerkleTree(addresses, keccak256, { hashLeaves: true, sortPairs: true })
await contract.addTree(tree.getRoot())
// save hashed addresses for later use
const hashedAddresses = addresses.map(address => keccal256(address))
// ...
To run function with whitelist
const keccal256 = require('keccak256')
const { MerkleTree } = require('merkletreejs')
const targetAddress = '0x...'
// this should be generated when adding the address to the whitelist
const hashedAddresses = []
const tree = new MerkleTree(hashedAddresses, keccal256, { hashLeaves: false, sortPairs: true })
const leaf = keccal256(targetAddress)
const proof = tree.getProof(leaf)
// proof is always needed for whitelist checking, input [] when not needed
await contract.fn(proof)
Contract Interface
Interface ERC721 with burn function supported
IERC721
IERC721Metadata
IERC721Enumerable
burn(uint256 tokenId)