Skip to content

Instantly share code, notes, and snippets.

@yograterol
Created July 19, 2021 05:24
Show Gist options
  • Save yograterol/4c7f03e7fc411e279c52b4be1e033b79 to your computer and use it in GitHub Desktop.
Save yograterol/4c7f03e7fc411e279c52b4be1e033b79 to your computer and use it in GitHub Desktop.
Dragonary Smart Contracts to Audit
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/drafts/ERC20Permit.sol";
import "./ERC20Capped.sol";
contract CoinaryToken is Context, AccessControl, ERC20Burnable, ERC20Capped, ERC20Permit {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
uint public constant MAX_DAILY_MINTING_AMOUNT = 2000000 ether;
uint private _daily_minting_amount = MAX_DAILY_MINTING_AMOUNT;
uint public nextMintingDate;
// Test values
address public constant TEAM_ADDRESS = 0x98Ea123e74d6aa89988efe856866bB0E27B61768;
address public constant INVESTOR_ADDRESS = 0x1F2d3c15cb55016dCbf4909065Dd501949a4e1fe;
address public constant AIRDROP_ADDRESS = 0xDB84042f12747369a4A41157408937dC29629Fd3;
// Production values
// address public constant TEAM_ADDRESS = 0x0;
// address public constant INVESTOR_ADDRESS = 0x0;
// address public constant AIRDROP_ADDRESS = 0x0;
/**
* @dev Grants `DEFAULT_ADMIN_ROLE` and `MINTER_ROLE` to the
* account that deploys the contract.
*
* See {ERC20-constructor}.
*/
constructor(
string memory name,
string memory symbol,
uint256 cap
) ERC20(name, symbol) ERC20Capped(cap) ERC20Permit(name) {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(MINTER_ROLE, _msgSender());
// Mint tokens for team
_mint(TEAM_ADDRESS, 50000000 ether);
// Mint tokens for investors
_mint(INVESTOR_ADDRESS, 160000000 ether);
// Mint tokens for Airdrop
_mint(AIRDROP_ADDRESS, 41000000 ether);
nextMintingDate = block.timestamp + 1 days;
}
/**
* @dev Creates `amount` new tokens for `to`.
*
* See {ERC20-_mint}.
*
* Requirements:
*
* - the caller must have the `MINTER_ROLE`.
* - the amount to mint must be less or equal to MAX_DAILY_MINTING_AMOUNT
*/
function mint(address to, uint256 amount) public virtual {
require(
hasRole(MINTER_ROLE, _msgSender()),
"CoinaryToken: must have minter role to mint"
);
require(amount <= MAX_DAILY_MINTING_AMOUNT, "CoinaryToken: The amount is highest than the MAX_DAILY_MINTING_AMOUNT");
require(amount <= _daily_minting_amount, "CoinaryToken: The amount is highest than the daily_minting_amount");
require(block.timestamp >= nextMintingDate, "CoinaryToken: You must wait 24 hours until the next minting");
_mint(to, amount);
nextMintingDate = block.timestamp + 1 days;
}
/**
* @dev Change the daily minting amount.
*
* Requirements:
*
* - the caller must have the `MINTER_ROLE`.
* - the amount to mint must be less or equal to MAX_DAILY_MINTING_AMOUNT
*/
function changeDailyMintingAmount(uint256 amount) public virtual {
require(
hasRole(DEFAULT_ADMIN_ROLE, _msgSender()),
"CoinaryToken: must have admin role to change the daily minting amount."
);
require(amount <= MAX_DAILY_MINTING_AMOUNT, "CoinaryToken: The amount is highest than the MAX_DAILY_MINTING_AMOUNT");
_daily_minting_amount = amount;
}
function dailyMintingAmount() public view virtual returns (uint) {
return _daily_minting_amount;
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual override(ERC20, ERC20Capped) {
super._beforeTokenTransfer(from, to, amount);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Context.sol";
contract DragonsERC721 is Context, AccessControl, ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdTracker;
mapping(uint256 => bool) private _burnedDragon;
// Events
event NewDragon(address player, uint256 dragonId);
event Burn(address indexed _called, uint256 _dragonId);
event Restore(address indexed _called, uint256 _dragonId, bool burnStatus);
// Access Control Roles
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
constructor() ERC721("Dragonary Dragons", "DRAGON") {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(MINTER_ROLE, _msgSender());
_setupRole(BURNER_ROLE, _msgSender());
_setBaseURI("https://items.dragonary.com/dragons/");
}
function mintDragon(address player) public returns (uint256) {
require(
hasRole(MINTER_ROLE, _msgSender()),
"DragonsERC721: must have minter role to mint"
);
_tokenIdTracker.increment();
uint256 newDragon = _tokenIdTracker.current();
_mint(player, newDragon);
emit NewDragon(player, newDragon);
return newDragon;
}
// Soft burn to avoid delete completely the dragon
function softBurnDragon(uint256 dragonId) public returns (bool) {
require(
hasRole(BURNER_ROLE, _msgSender()),
"DragonsERC721: must have burner role"
);
require(_exists(dragonId), "DragonsERC721: Dragon didn't exist");
_burnedDragon[dragonId] = true;
emit Burn(_msgSender(), dragonId);
return true;
}
function isBurned(uint256 dragonId) public view virtual returns (bool) {
return _burnedDragon[dragonId];
}
/*
* Use only if some issues with the server game happens
* ONLY ADMIN CAN CALL THIS FUNCTION
*/
function restoreDragon(uint256 dragonId, bool burnStatus) public returns (bool) {
require(
hasRole(DEFAULT_ADMIN_ROLE, _msgSender()),
"DragonsERC721: must have admin role"
);
require(_exists(dragonId), "DragonsERC721: Dragon didn't exist");
_burnedDragon[dragonId] = burnStatus;
emit Restore(_msgSender(), dragonId, burnStatus);
return true;
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override(ERC721) {
require(_burnedDragon[tokenId] == false, "DragonsERC721: Dragon is burned");
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
/**
* @dev Extension of {ERC20} that adds a cap to the supply of tokens.
*/
abstract contract ERC20Capped is ERC20 {
using SafeMath for uint256;
uint256 private _cap;
/**
* @dev Sets the value of the `cap`. This value is immutable, it can only be
* set once during construction.
*/
constructor (uint256 cap_) {
require(cap_ > 0, "ERC20Capped: cap is 0");
_cap = cap_;
}
/**
* @dev Returns the cap on the token's total supply.
*/
function cap() public view virtual returns (uint256) {
return _cap;
}
/**
* @dev See {ERC20-_beforeTokenTransfer}.
*
* Requirements:
*
* - minted tokens must not cause the total supply to go over the cap.
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
if (from == address(0)) { // When minting tokens
require(totalSupply().add(amount) <= cap(), "ERC20Capped: cap exceeded");
}
if (to == address(0)) { // When burning tokens
_cap = _cap.sub(amount);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
/**
* @title ERC20VestingWallet
* @dev This contract handles the vesting of ERC20 tokens for a given beneficiary. Custody of multiple tokens can be
* given to this contract, which will release the token to the beneficiary following a given vesting schedule. The
* vesting schedule is customizable through the {vestedAmount} function.
*
* Any token transferred to this contract will follow the vesting schedule as if they were locked from the beginning.
* Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly)
* be immediately releasable.
*/
contract ERC20VestingWallet is Context {
using SafeMath for uint256;
event TokensReleased(address token, uint256 amount);
mapping(address => uint256) private _released;
address private immutable _beneficiary;
uint256 private immutable _start;
uint256 private immutable _duration;
modifier onlyBeneficiary() {
require(beneficiary() == _msgSender(), "ERC20VestingWallet: access restricted to beneficiary");
_;
}
/**
* @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet.
*/
constructor(
address beneficiaryAddress
) {
require(beneficiaryAddress != address(0), "ERC20VestingWallet: beneficiary is zero address");
_beneficiary = beneficiaryAddress;
_start = block.timestamp;
// Mainnet Value
// _duration = 10 years;
// Test Value
_duration = 1 days;
}
/**
* @dev Getter for the beneficiary address.
*/
function beneficiary() public view virtual returns (address) {
return _beneficiary;
}
/**
* @dev Getter for the start timestamp.
*/
function start() public view virtual returns (uint256) {
return _start;
}
/**
* @dev Getter for the vesting duration.
*/
function duration() public view virtual returns (uint256) {
return _duration;
}
/**
* @dev Amont of token already released
*/
function released(address token) public view returns (uint256) {
return _released[token];
}
/**
* @dev Release the tokens that have already vested.
*
* Emits a {TokensReleased} event.
*/
function release(address token) public virtual {
uint256 releasable = vestedAmount(token, block.timestamp) - released(token);
_released[token] += releasable;
emit TokensReleased(token, releasable);
SafeERC20.safeTransfer(IERC20(token), beneficiary(), releasable);
}
/**
* @dev Calculates the amount that has already vested. Default implementation is a linear vesting curve.
*/
function vestedAmount(address token, uint256 timestamp) public view virtual returns (uint256) {
if (timestamp < start()) {
return 0;
} else if (timestamp >= start().add(duration())) {
return _historicalBalance(token);
} else {
return _historicalBalance(token).mul(timestamp.sub(start())).div(duration());
}
}
/**
* @dev Calculates the historical balance (current balance + already released balance).
*/
function _historicalBalance(address token) internal view virtual returns (uint256) {
return IERC20(token).balanceOf(address(this)) + released(token);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment