文件 1 的 1:LERC20MintableBurnable.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) {
return msg.data;
}
}
interface ILERC20 {
function name() external view returns (string memory);
function admin() external view returns (address);
function getAdmin() external view returns (address);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
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);
function increaseAllowance(address _spender, uint256 _addedValue) external returns (bool);
function decreaseAllowance(address _spender, uint256 _subtractedValue) external returns (bool);
function transferOutBlacklistedFunds(address[] calldata _from) external;
function setLosslessAdmin(address _newAdmin) external;
function transferRecoveryAdminOwnership(address _candidate, bytes32 _keyHash) external;
function acceptRecoveryAdminOwnership(bytes memory _key) external;
function proposeLosslessTurnOff() external;
function executeLosslessTurnOff() external;
function executeLosslessTurnOn() external;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
event NewAdmin(address indexed _newAdmin);
event NewRecoveryAdminProposal(address indexed _candidate);
event NewRecoveryAdmin(address indexed _newAdmin);
event LosslessTurnOffProposal(uint256 _turnOffDate);
event LosslessOff();
event LosslessOn();
}
interface ILssController {
function whitelist(address _adr) external view returns (bool);
function blacklist(address _adr) external view returns (bool);
function admin() external view returns (address);
function recoveryAdmin() external view returns (address);
function setAdmin(address _newAdmin) external;
function setRecoveryAdmin(address _newRecoveryAdmin) external;
function setWhitelist(address[] calldata _addrList, bool _value) external;
function setBlacklist(address[] calldata _addrList, bool _value) external;
function beforeTransfer(address _sender, address _recipient, uint256 _amount) external;
function beforeTransferFrom(address _msgSender, address _sender, address _recipient, uint256 _amount) external;
function beforeApprove(address _sender, address _spender, uint256 _amount) external;
function beforeIncreaseAllowance(address _msgSender, address _spender, uint256 _addedValue) external;
function beforeDecreaseAllowance(address _msgSender, address _spender, uint256 _subtractedValue) external;
function beforeMint(address _to, uint256 _amount) external;
function beforeBurn(address _account, uint256 _amount) external;
function afterTransfer(address _sender, address _recipient, uint256 _amount) external;
event AdminChange(address indexed _newAdmin);
event RecoveryAdminChange(address indexed _newAdmin);
event PauseAdminChange(address indexed _newAdmin);
}
contract LERC20 is Context, ILERC20 {
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
address public recoveryAdmin;
address private recoveryAdminCandidate;
bytes32 private recoveryAdminKeyHash;
address override public admin;
uint256 public timelockPeriod;
uint256 public losslessTurnOffTimestamp;
bool public isLosslessOn = true;
ILssController public lossless;
constructor(uint256 totalSupply_, string memory name_, string memory symbol_, uint8 decimals_, address admin_, address recoveryAdmin_, uint256 timelockPeriod_, address lossless_) {
_mint(_msgSender(), totalSupply_);
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
admin = admin_;
recoveryAdmin = recoveryAdmin_;
recoveryAdminCandidate = address(0);
recoveryAdminKeyHash = "";
timelockPeriod = timelockPeriod_;
losslessTurnOffTimestamp = 0;
lossless = ILssController(lossless_);
}
modifier lssAprove(address spender, uint256 amount) {
if (isLosslessOn) {
lossless.beforeApprove(_msgSender(), spender, amount);
}
_;
}
modifier lssTransfer(address recipient, uint256 amount) {
if (isLosslessOn) {
lossless.beforeTransfer(_msgSender(), recipient, amount);
}
_;
}
modifier lssTransferFrom(address sender, address recipient, uint256 amount) {
if (isLosslessOn) {
lossless.beforeTransferFrom(_msgSender(),sender, recipient, amount);
}
_;
}
modifier lssIncreaseAllowance(address spender, uint256 addedValue) {
if (isLosslessOn) {
lossless.beforeIncreaseAllowance(_msgSender(), spender, addedValue);
}
_;
}
modifier lssDecreaseAllowance(address spender, uint256 subtractedValue) {
if (isLosslessOn) {
lossless.beforeDecreaseAllowance(_msgSender(), spender, subtractedValue);
}
_;
}
modifier onlyRecoveryAdmin() {
require(_msgSender() == recoveryAdmin, "LERC20: Must be recovery admin");
_;
}
function transferOutBlacklistedFunds(address[] calldata from) override external {
require(_msgSender() == address(lossless), "LERC20: Only lossless contract");
uint256 fromLength = from.length;
uint256 totalAmount = 0;
for (uint256 i = 0; i < fromLength; i++) {
address fromAddress = from[i];
uint256 fromBalance = _balances[fromAddress];
_balances[fromAddress] = 0;
totalAmount += fromBalance;
emit Transfer(fromAddress, address(lossless), fromBalance);
}
_balances[address(lossless)] += totalAmount;
}
function setLosslessAdmin(address newAdmin) override external onlyRecoveryAdmin {
require(newAdmin != admin, "LERC20: Cannot set same address");
emit NewAdmin(newAdmin);
admin = newAdmin;
}
function transferRecoveryAdminOwnership(address candidate, bytes32 keyHash) override external onlyRecoveryAdmin {
recoveryAdminCandidate = candidate;
recoveryAdminKeyHash = keyHash;
emit NewRecoveryAdminProposal(candidate);
}
function acceptRecoveryAdminOwnership(bytes memory key) override external {
require(_msgSender() == recoveryAdminCandidate, "LERC20: Must be canditate");
require(keccak256(key) == recoveryAdminKeyHash, "LERC20: Invalid key");
emit NewRecoveryAdmin(recoveryAdminCandidate);
recoveryAdmin = recoveryAdminCandidate;
recoveryAdminCandidate = address(0);
}
function proposeLosslessTurnOff() override external onlyRecoveryAdmin {
require(losslessTurnOffTimestamp == 0, "LERC20: TurnOff already proposed");
require(isLosslessOn, "LERC20: Lossless already off");
losslessTurnOffTimestamp = block.timestamp + timelockPeriod;
emit LosslessTurnOffProposal(losslessTurnOffTimestamp);
}
function executeLosslessTurnOff() override external onlyRecoveryAdmin {
require(losslessTurnOffTimestamp != 0, "LERC20: TurnOff not proposed");
require(losslessTurnOffTimestamp <= block.timestamp, "LERC20: Time lock in progress");
isLosslessOn = false;
losslessTurnOffTimestamp = 0;
emit LosslessOff();
}
function executeLosslessTurnOn() override external onlyRecoveryAdmin {
require(!isLosslessOn, "LERC20: Lossless already on");
losslessTurnOffTimestamp = 0;
isLosslessOn = true;
emit LosslessOn();
}
function getAdmin() override public view virtual returns (address) {
return admin;
}
function name() override public view virtual returns (string memory) {
return _name;
}
function symbol() override public view virtual returns (string memory) {
return _symbol;
}
function decimals() override public view virtual returns (uint8) {
return _decimals;
}
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 lssTransfer(recipient, amount) 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 lssAprove(spender, amount) returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override lssTransferFrom(sender, recipient, amount) returns (bool) {
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "LERC20: transfer amount exceeds allowance");
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), currentAllowance - amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) override public virtual lssIncreaseAllowance(spender, addedValue) returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) override public virtual lssDecreaseAllowance(spender, subtractedValue) returns (bool) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "LERC20: 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), "LERC20: transfer from the zero address");
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "LERC20: 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), "LERC20: mint to the zero address");
_totalSupply += amount;
unchecked {
_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");
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
}
contract LERC20MintableBurnable is Context, LERC20 {
constructor(
uint256 totalSupply_,
string memory name_,
string memory symbol_,
uint8 decimals_,
address admin_,
address recoveryAdmin_,
uint256 timelockPeriod_,
address lossless_
) LERC20(
totalSupply_,
name_,
symbol_,
decimals_,
admin_,
recoveryAdmin_,
timelockPeriod_,
lossless_
) {}
modifier lssBurn(address account, uint256 amount) {
if (isLosslessOn) {
lossless.beforeBurn(account, amount);
}
_;
}
modifier lssMint(address account, uint256 amount) {
if (isLosslessOn) {
lossless.beforeMint(account, amount);
}
_;
}
function burn(uint256 amount) public virtual lssBurn(_msgSender(), amount) {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual lssBurn(account, amount) {
uint256 currentAllowance = allowance(account, _msgSender());
require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance");
unchecked {
_approve(account, _msgSender(), currentAllowance - amount);
}
_burn(account, amount);
}
function mint(address to, uint256 amount) public virtual lssMint(to, amount) {
require(_msgSender() == admin, "LERC20: Must be admin");
_mint(to, amount);
}
function setLossless(address _newLossless) external onlyRecoveryAdmin {
require(_newLossless != address(0), "LERC20: Cannot set address(0)");
lossless = ILssController(_newLossless);
}
}