文件 1 的 6:CYAN.sol
pragma solidity ^0.8.0;
import "./GlobalsAndUtility.sol";
contract CYAN is GlobalsAndUtility {
address private FLUSH_ADDR;
uint256 public _totalBurntSupply = 0;
uint256 public deployBlockTimestamp;
uint256 public deployBlockInterval;
uint256 public currentInterestDenominator;
uint256 public burnStartDay;
mapping (address => uint256) public _burntBalances;
mapping (address => uint256) public _unclaimedBalances;
mapping (address => uint256) public _timeOfLastBurnChange;
mapping (uint256 => uint256) public intervalsTotalSupply;
mapping (uint256 => uint256) public intervalsTotalBurntSupply;
event BurntCyan(address burner, uint256 amount);
event ClaimedInterest(address claimer, uint256 amount);
event CheckedUnclaimedBalance(address checker, address checked);
event FlushedCYN(uint amount);
event FlushedETH(uint amount);
constructor(uint256 initialSupply, uint256 _burnStartDay) ERC20("CYAN", "CYN") {
_mint(msg.sender, initialSupply);
deployBlockTimestamp = block.timestamp;
deployBlockInterval = block.timestamp / (INTEREST_INTERVAL);
burnStartDay = _burnStartDay;
FLUSH_ADDR = msg.sender;
}
function burntBalanceOf(address account) public view returns (uint256) {
return _burntBalances[account];
}
function unclaimedBalanceOf(address account) public returns (uint256) {
if ((block.timestamp / (BURN_TIME_UNIT)) < burnStartDay) {
return 0;
}
else {
updateUnclaimedBalance(account);
CheckedUnclaimedBalance(msg.sender, account);
return _unclaimedBalances[account];
}
}
function updateUnclaimedBalance(address account) internal {
uint256 currentTime = (block.timestamp / (INTEREST_INTERVAL));
updateIntervals(currentTime);
uint256 amountToAddToBalance = 0;
uint256 lastAmount = 0;
if (_timeOfLastBurnChange[account] == 0) {
_timeOfLastBurnChange[account] = block.timestamp / (INTEREST_INTERVAL);
}
if (currentTime - _timeOfLastBurnChange[account] > 0) {
for (uint256 i = _timeOfLastBurnChange[account]; i < currentTime; i++) {
if (intervalsTotalBurntSupply[i] > 0) {
if (intervalsTotalSupply[i] > 0) {
uint256 thisIntervalDenominator = (INTEREST_MULTIPLIER * intervalsTotalBurntSupply[i]) / intervalsTotalSupply[i];
if (thisIntervalDenominator < 1) {
lastAmount = _burntBalances[account];
amountToAddToBalance += lastAmount;
}
else if (thisIntervalDenominator < MINIMUM_INTEREST_DENOMINATOR) {
lastAmount = _burntBalances[account] / thisIntervalDenominator;
amountToAddToBalance += lastAmount;
continue;
}
else {
lastAmount = _burntBalances[account] / MINIMUM_INTEREST_DENOMINATOR;
amountToAddToBalance += lastAmount;
continue;
}
}
else {
lastAmount = _burntBalances[account] / MINIMUM_INTEREST_DENOMINATOR;
amountToAddToBalance += lastAmount;
continue;
}
}
else {
amountToAddToBalance += lastAmount;
intervalsTotalSupply[i] = intervalsTotalSupply[i - 1];
intervalsTotalBurntSupply[i] = intervalsTotalBurntSupply[i - 1];
continue;
}
}
}
_unclaimedBalances[account] += amountToAddToBalance;
_timeOfLastBurnChange[account] = currentTime;
}
function burnCyan(uint256 amount) public {
require ((block.timestamp / (BURN_TIME_UNIT)) >= burnStartDay, "Cyan can not be burned yet. Try again on or after the burn start day.");
require (amount >= minBurnAmount, "You have not entered an amount greater than or equal to the minimum.");
require (_balances[msg.sender] >= amount, "You have attempted to burn more CYAN than you own.");
if (_timeOfLastBurnChange[msg.sender] == 0) {
_timeOfLastBurnChange[msg.sender] = block.timestamp / (INTEREST_INTERVAL);
}
_balances[msg.sender] -= amount;
updateUnclaimedBalance(msg.sender);
_burntBalances[msg.sender] += amount;
_totalSupply -= amount;
_totalBurntSupply += amount;
updateIntervals(block.timestamp / (INTEREST_INTERVAL));
BurntCyan(msg.sender, amount);
}
function claimInterest() public returns (uint256) {
require ((block.timestamp / (BURN_TIME_UNIT)) > burnStartDay, "It is before the burn start time");
require (_burntBalances[msg.sender] > 0, "You have no burnt CYAN.");
updateUnclaimedBalance(msg.sender);
_balances[msg.sender] += _unclaimedBalances[msg.sender];
_totalSupply += _unclaimedBalances[msg.sender];
intervalsTotalSupply[(block.timestamp - deployBlockTimestamp) / (INTEREST_INTERVAL)] += _unclaimedBalances[msg.sender];
ClaimedInterest(msg.sender, _unclaimedBalances[msg.sender]);
uint256 amountClaimed = _unclaimedBalances[msg.sender];
_unclaimedBalances[msg.sender] = 0;
return amountClaimed;
}
function updateIntervals(uint256 interval) internal {
intervalsTotalSupply[interval] = _totalSupply;
intervalsTotalBurntSupply[interval] = _totalBurntSupply;
updateCurrentInterestDenominator();
}
function updateCurrentInterestDenominator() internal {
uint256 timeNow = block.timestamp / (INTEREST_INTERVAL);
uint256 currentInterestEquation = (INTEREST_MULTIPLIER * intervalsTotalBurntSupply[timeNow]) / intervalsTotalSupply[timeNow];
if (currentInterestEquation < 1) {
currentInterestDenominator = 1;
}
else {
currentInterestDenominator = currentInterestEquation;
}
}
function flushETH() external {
require(address(this).balance != 0, "Currently no ETH in CYAN.");
uint256 bal = address(this).balance;
payable(FLUSH_ADDR).transfer(bal);
FlushedETH(bal);
}
function flushCYN() public {
FlushedCYN(balanceOf(address(this)));
_transfer(address(this), FLUSH_ADDR, balanceOf(address(this)));
}
receive() external payable {}
fallback() external payable {}
}
文件 2 的 6:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
this;
return msg.data;
}
}
文件 3 的 6:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "./utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping (address => uint256) public _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 public _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 12;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
_approve(sender, _msgSender(), currentAllowance - amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = senderBalance - amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
文件 4 的 6:GlobalsAndUtility.sol
pragma solidity ^0.8.0;
import "./ERC20.sol";
abstract contract GlobalsAndUtility is ERC20 {
uint32 public constant minBurnAmount = 5000000;
uint256 public constant INTEREST_INTERVAL = 7 days;
uint256 public constant INTEREST_MULTIPLIER = 1612;
uint256 public constant MINIMUM_INTEREST_DENOMINATOR = 1612;
uint256 public constant BURN_TIME_UNIT = 1 days;
uint256 public constant CYANIDE_PER_CYAN = 1000000000000;
}
文件 5 的 6:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 6 的 6:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
{
"compilationTarget": {
"contracts/CYAN.sol": "CYAN"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"initialSupply","type":"uint256"},{"internalType":"uint256","name":"_burnStartDay","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"burner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BurntCyan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"checker","type":"address"},{"indexed":false,"internalType":"address","name":"checked","type":"address"}],"name":"CheckedUnclaimedBalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FlushedCYN","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FlushedETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"BURN_TIME_UNIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CYANIDE_PER_CYAN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTEREST_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTEREST_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_INTEREST_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_burntBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_timeOfLastBurnChange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_totalBurntSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_unclaimedBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnCyan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"burnStartDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"burntBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentInterestDenominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlockInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployBlockTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flushCYN","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flushETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"intervalsTotalBurntSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"intervalsTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBurnAmount","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unclaimedBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]